Java és un llenguatge orientat a objectes de primera classe. Amb l'excepció dels tipus de dades primitius, tot a Java és un objecte. Fins i tot una matriu és un objecte. Cada classe crea instàncies que són objectes. No hi ha manera de definir solament una funció / mètode que quedi a Java per si mateix. No hi ha manera de passar un mètode com a argument o retornar un cos del mètode per a aquesta instància.
Les classes internes anònimes eren el recurs habitual per intentar estalviar codi escrit.
En resum, no és fàcil passar mètodes plans a Java com a arguments. A causa d'aquesta limitació, Java 8 afegeix una funció de nivell de llenguatge que es diu Expressions Lambda.
Un llenguatge funcional ofereix un closure, que té bastants avantatges sobre la manera tradicional d'escriure aplicacions. Un closure és una funció o referència a una funció, juntament amb l'entorn de referència. Una taula que guarda una referència de cadascuna de les variables no locals d'aquesta funció. El més semblant que Java pot proporcionar al closure són les expressions lambda. Hi ha una diferència significativa entre un closure i una expressió lambda, almenys l'expressió Lambda ofereix una bona alternativa al closure. La diferència és que les Lambdas no són funcions, sinó objectes.
Què són?
Una expressió lambda és com una funció anònima. En poques paraules, es tracta d'un mètode sense una declaració, és a dir, modificador d'accés, la declaració del valor de retorn i el nom.
És una espècie de taquigrafia que us permet escriure un mètode al mateix lloc on s'utilitzarà. Especialment útil en llocs on s'utilitza un mètode una sola vegada, i la definició del mètode és curta. Això estalvia l'esforç de declarar i escriure un mètode independent per a la classe que el conté.
Les expressions lambda a Java s'escriuen utilitzant la sintaxi:
(arguments) → (cos)
Exemple
int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 }
Estructura
Una expressió lambda pot tenir zero, un o més paràmetres.
El tipus dels paràmetres pot estar declarat explícitament o es pot inferir a partir del context, per exemple (int a) és el mateix que (a).
Els paràmetres s'inclouen entre parèntesis i separats per comes, per exemple (a,b) o (int a, int b) o (String a, int b, float c).
Els parèntesis buits s'utilitzen per representar un conjunt buit de paràmetres, per exemple () → 42
Quan hi ha un únic paràmetre, si el seu tipus és inferit, no és obligatori l'ús de parèntesis. Per exemple a → return a*a
El cos de les expressions lambda pot contenir zero, una o més declaracions.
Si el cos de l'expressió lambda té una declaració única, les claus no són obligatòries i el tipus de retorn de la funció anònima és el mateix que el de l'expressió del cos.
Quan hi ha més d'una sentència al cos, aquestes han d'estar encloses entre claus (un bloc de codi) i el tipus de retorn de la funció anònima és el mateix que el tipus de valor retornat dins del bloc de codi, o no seran vàlides si no retorna res.
Interfícies funcionals
A Java, una interfície és un classificador sense mètodes definits ni atributs declarats.
De la mateixa manera, una interfície funcional és una interfície amb un únic mètode abstracte declarat en aquesta.
java.lang.Runnable és un exemple d'una interfície funcional. Només hi ha un mètode void run() declarat a la interfície runnable. De la mateixa manera la interfície ActionListener és també una interfície funcional. Utilitzem les classes internes anònimes per crear instàncies d'objectes d'interfície funcional. Amb expressions lambda, això es pot simplificar. Cada expressió lambda es pot assignar implícitament a una interfície anomenada interfície funcional. Per exemple, podem crear la referència de la interfície runnable com a expressió lambda, com podem veure:
Runnable r = () -> System.out.println("hola món");
Aquest tipus de conversió la realitza el compilador quan nosaltres no especifiquem la interfície funcional. Per exemple:
new Thread( () -> System.out.println("hola món") ).start();
Així, en el codi anterior, el compilador dedueix automàticament que l'expressió lambda pot llançar la interfície runnable des del constructor de la classe:
Thread public Thread(Runnable r){}
@FunctionalInterface
public interface TrabajadorInterfaz{
public void hacerAlgo();
}
Les interfícies funcionals són interfícies amb un sol mètode diferit. Una vegada definida la interfície funcional, podem simplement utilitzar-la en la nostra API i aprofitar les expressions lambda.