1. Metode de funcționare

Dacă o interfață are o singură metodă , unei variabile de acel tip de interfață i se poate atribui o valoare dată de o expresie lambda (funcția lambda). Astfel de interfețe au devenit cunoscute ca interfețe funcționale (după ce Java a adăugat suport pentru funcțiile lambda).

De exemplu, Java are interfața Consumer<Type>, care are accept(Type obj)metoda. De ce este nevoie de această interfață?

În Java 8, colecțiile au o forEach()metodă, care vă permite să efectuați o anumită acțiune pentru fiecare element al colecției . Și aici Consumer<T>interfața funcțională este folosită pentru a trece acțiunea metodei forEach().

Iată cum puteți afișa toate elementele unei colecții :

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Hello", "how's", "life?");

list.forEach( (s) -> System.out.println(s) );
Afișarea tuturor elementelor unei colecții (folosind o expresie lambda)

Compilatorul va converti codul de mai sus în codul de mai jos:

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Hello", "how's", "life?");

list.forEach(new Consumer<String>()
{
   public void accept(String s)
   {
      System.out.println(s));
   }
});
Afișarea tuturor elementelor unei colecții (folosind o clasă anonimă)

Prima versiune este cu siguranță mai scurtă decât a doua. Și în timp ce codul cu expresii lambda este greu de citit, codul cu clase interne anonime este uneori și mai greu de citit.



2. Metodă de referință

Cu toate acestea, codul nostru de expresie lambda poate fi scris și mai scurt.

În primul rând, puteți omite parantezele din jurul sparametrului:

list.forEach( (s) -> System.out.println(s) );
Inainte de
list.forEach( s -> System.out.println(s) );
După

Acest lucru se poate face numai dacă există un singur parametru . Dacă există mai mulți parametri, atunci trebuie să utilizați paranteze .

Și în al doilea rând, puteți scrie așa:

list.forEach( System.out::println );
Cea mai compactă notație

Aceasta este exact aceeași notație. Rețineți că nu există paranteze după println.

Aici avem același cod - un apel de metodă:

object::method
x -> object.method(x)

Gândește-te: am vrut să realizăm o acțiune pentru fiecare element al listcolecției. Dacă acțiunea este un singur apel de funcție (cum ar fi println()), atunci are sens să treceți pur și simplu funcția metodei ca parametru.

Dar cum îi explicăm compilatorului că vrem să trecem metoda în loc să o numim? Pentru a face acest lucru, în loc de operatorul punct, folosim două puncte înainte de numele metodei. Un singur două puncte este deja folosită pentru a indica operatorul ternar.

Aceasta este cea mai simplă și mai compactă notație.



3. Constructor

Referințele la metode cu două puncte duble sunt foarte utile atunci când lucrăm cu fluxuri I/O. Veți vedea asta puțin mai târziu.

Între timp, să vorbim despre 3 moduri populare de a trece o referință de metodă:

Referire la o metodă a unui obiect

Pentru a transmite o referință la o metodă a unui obiect, trebuie să scrieți ceva de genul . Acest cod este echivalent cu .object::method
x -> object.method(x)

Specialele thisși supervariabilele pot fi folosite ca obiect.

Referire la o metodă a unei clase

Pentru a transmite o referință la o metodă statică, trebuie să scrieți ceva de genul . Acest cod este convertit în cod similarclass::methodx -> class.method(x);

Referire la un constructor

Un constructor se comportă în mod similar cu o metodă de clasă statică, deci puteți transmite și o referință unui constructor. Așa arată: .class::new

De exemplu, puteți evita ștergerea tipului pentru colecții și puteți transmite toArray()metodei o referință unui constructor care va crea matricea dorită:toArray(int[]::new);