ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 150
Numărul 149 Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 23
Abonament PDF

Java 8, expresii lambda şi nu numai

Silviu Dumitrescu




PROGRAMARE

Este primăvară... vremea schimbărilor şi a speranţelor... Oracle contribuie la toate acestea cu o nouă versiune a platformei Java standard. Este vorba de versiunea 8, lansată în martie 2014. Începând cu acest număr al revistei Today Software Magazine doresc să modific stilul articolelor pe care le scriu. Nu pot spune că abandonez ideea recenziilor, care reprezintă o sursă importantă de popularizare a cărţilor valoroase din biblioteca IT, dar voi adăuga şi articole cu un grad mai mare de tehnicitate. Urmăresc prin aceasta ca cititorii revistei să fie „stârniţi” în a descoperi ce este nou şi performant în lumea dezvoltării de aplicaţii software.

Mă bucur foarte mult că acest număr este lansat şi în Braşov şi, deşi este prima lansare aici, sper să fie urmată de multe altele. Braşovul are un potenţial enorm, iar eu iubesc incredibil acest oraş.

Java SE8 este considerată revoluţionară, prin câteva dintre noile caracteristici introduse. Programată iniţial pentru luna septembrie 2013, lansarea a fost amânată pentru martie 2014. Motivele sunt numeroase, dar ţin în special de corectarea bug-urilor şi de îmbunătăţirea securităţii, mai ales pe parte de client, având ca principal motiv JavaFX.

Multe sunt modificările şi adăugările făcute în limbaj, dar probabil cea mai spectaculoasă este introducerea abilităţilor lambda. Acestea sunt văzute ca un important beneficiu în programarea paralelă. De fapt, eforturile pentru creşterea performanţei în programarea paralelă s-au văzut încă din versiunea 7, introducerea framework-ului Fork-Join este un singur exemplu.

În prima parte a articolului mă voi orienta cu precădere spre lambda expresii, în partea finală voi prezenta succint un engine JavaScript nou nouţ, pentru ca în articolele următoare doresc să aduc în discuţie şi alte subiecte legate de Java SE٨.

O funcţie lambda (funcţie anonimă) este o funcţie definită şi apelată fără a fi legată de un identificator. Funcţiile lambda sunt o formă de funcţii ,,incuibate” (nested functions) în sensul că permit accesul la variabilele din domeniul funcţiei în care sunt conţinute.

Funcţiile anonime au fost introduse de către Alonzo Church în anul 1936, în teoria sa despre calculele lambda.

În limbajele de programare, funcţiile anonime sunt implementate din anul 1958 ca parte a limbajului Lisp. În unele limbajele orientate pe obiect, precum Java, apar concepte similare, precum clasele anonime. Abia în versiunea 8 a limbajului Java sunt adăugate şi funcţiile anonime. Alte limbaje, precum C#, JavaScript, Perl, Python, Ruby ofereau demult suport pentru acest concept.

Lambda expresiile ne permit să creăm instanţe ale claselor cu o singură metodă într-un mod mult mai compact.

O lambda expresie constă:

O interfaţă funcţională (functional interface) este orice interfaţă ce conţine doar o metodă abstractă. Din această cauză putem omite numele metodei atunci când implementăm interfaţa şi putem elimina folosirea claselor anonime. În locul lor vom avea lambda expresii. O interfaţă funcţională este anotată cu @FunctionalInterface. Pentru a înţelege modul în care se lucrează cu lambda expresii am construit un mic exemplu prin care am creat colecţii de obiecte sortate după diverse criterii. Implementarea interfeţei Comparator a fost făcută într-o clasă anonimă, folosind lambda expresii. Implementarea cu lambda expresii a fost posibilă pentru că în versiunea 8 Comparator este anotată cu @FunctionalInterface.

Elementul de bază al colecţiei este clasa Product, care este o clasă POJO cu getter-i și setter-i. Clasa conţine două implementări anonime ale comparatorului, determinând sortarea crescătoare respectiv descrescătoare a elementelor colecţiei.

package model;
import java.util.Comparator;
public class Product {
    private String name;
    private int price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public void printProduct() {
        System.out.println(this.toString());
    }

    @Override
    public String toString() {
     return "Product [name=" + name + ", price=" + price + "]";
    }

    public static Comparator 
     ascendingPrice = (p1, p2) -> {
      return p1.getPrice() - p2.getPrice();
    };

    public static Comparator 
     descendingPrice = (p1, p2) -> {
      return p2.getPrice() - p1.getPrice();
    }
}

Clasa de test va aduce ceva în plus faţă de o clasă cunoscută până în versiunea 8. Procesarea colecţiei nu se va face cu un foreach clasic. Ca parte a API-ului Collections avem noul API java.util.stream ce oferă suport pentru operaţii funcţionale pe stream-uri de elemente. În exemplul nostru vom folosi o interfaţă de bază a acestui API şi anume Consumer, care reprezintă o operaţie ce acceptă un singur argument de intrare şi nu returnează ceva. Cu Consumer vom putea folosi lambda expresii:

import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;

import model.Product;

public class TestLambda {

  public static void processProducts(
    Set products, Consumer block) {
      for (Product p : products) {
             block.accept(p);
      }
  }

  public static void main(String[] args) {

    Product p1 = new Product();
    p1.setName("onion");
    p1.setPrice(10);
    Product p2 = new Product();
    p2.setName("tomato");
    p2.setPrice(20);

    Set ascendingPriceProducts = new TreeSet<>(Product.ascendingPrice);

    ascendingPriceProducts.add(p1);
    ascendingPriceProducts.add(p2);

    System.out.println("In ascending order:");
    processProducts(ascendingPriceProducts, p -> p.printProduct());

    Set descendingPriceProducts = new TreeSet<>(Product.descendingPrice);

    descendingPriceProducts.add(p1);
    descendingPriceProducts.add(p2);

    System.out.println("In descending order:”);
    processProducts(descendingPriceProducts, p -> p.printProduct());

  }
}

Ca urmare a folosirii API-ului stream operaţiile efectuate pe o colecţie pot fi mult mai complexe decât cele ilustrate în exemplu şi anume: filtrarea după un predicat de selecţie, maparea obiectului filtrat, respectiv executarea unei acţiuni pe fiecare obiect mapat. Eu am prezentat doar ultima operaţie. Acestea se numesc operaţii agregat.

Observaţia pe care vreau să o fac codului anterior este că implementarea comparatorului ţine loc de suprascriere a funcţiei equals(), fapt ce poate fi dovedit prin modificarea, în cod, la valori egale a preţului.

Pe lângă lambda expresii, o caracteristică importantă, evident alături de modificările sintactice şi introducerea de API-uri noi, este dezvoltarea engine-ului JavaScript Nashorn (se pronunţă naz-horn). Prin acesta se pot integra script-uri JavaScript în codul Java clasic. Acest engine se bazează pe standardul ECMAScript 262. Este un engine scris complet de la zero având ca obiectiv creşterea performanţei. Este astfel, complet diferit faţă de engine-ul deja existent Rhino.

Voi da doar un mic exemplu de folosire a acestui engine, urmând ca în viitor să prezint mai multe detalii:

import javax.script.*;

public class EvalScript {
  public static void main(String[] args) throws Exception {
    // create a script engine manager
    ScriptEngineManager factory = new ScriptEngineManager();

    // create a Nashorn script engine
    ScriptEngine engine = factory.getEngineByName("nashorn");

    // evaluate JavaScript statement
    try {
      engine.eval(“print(‘Hello, World!’);”);
    } catch (final ScriptException se) {
      se.printStackTrace();
    }
  }
}

Rulând acest exemplu vom obține la consolă "Hello, World!".

Ca ultimă observaţie, am folosit pentru editare Eclipse Kepler iar de pe Marketplace am adus Eclipse Java, 8 Support (for Kepler SR2) JDT, PDE 1.0.0. Aceasta, până va apare Eclipse Luna (probabil în mai). Ca versiune de Java am utilizat jdk 1.8.0_05.

Sper că v-am stârnit interesul pentru Java 8 şi ca de obicei aştept cu mare plăcere discuţiile cu cei interesaţi.

Noile mele date de contact sunt: Silviu.Dumitrescu@accesa.eu

NUMĂRUL 149 - Development with AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects

Silviu Dumitrescu a mai scris