1. Funktionsmetoder

Hvis en grænseflade kun har én metode , kan en variabel af denne grænsefladetype tildeles en værdi givet af et lambda-udtryk (lambda-funktion). Sådanne grænseflader blev kendt som funktionelle grænseflader (efter Java tilføjede understøttelse af lambda-funktioner).

For eksempel har Java grænsefladen Consumer<Type>, som har accept(Type obj)metoden. Hvorfor er denne grænseflade nødvendig?

I Java 8 har samlinger en forEach()metode, som lader dig udføre en handling for hvert element i samlingen . Og her Consumer<T>bruges den funktionelle grænseflade til at videregive handlingen til forEach()metoden.

Sådan kan du vise alle elementer i en samling :

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

list.forEach( (s) -> System.out.println(s) );
Visning af alle elementer i en samling (ved hjælp af et lambda-udtryk)

Compileren vil konvertere koden ovenfor til koden nedenfor:

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));
   }
});
Visning af alle elementer i en samling (ved hjælp af en anonym klasse)

Den første version er bestemt kortere end den anden. Og mens kode med lambda-udtryk er svær at læse, er kode med anonyme indre klasser nogle gange endnu sværere at læse.



2. Metodehenvisning

Vores lambda- udtrykskode kan dog skrives endnu kortere.

Først kan du udelade parenteserne omkring sparameteren:

list.forEach( (s) -> System.out.println(s) );
Før
list.forEach( s -> System.out.println(s) );
Efter

Dette kan kun gøres, hvis der er én parameter . Hvis der er flere parametre, skal du bruge parenteser .

Og for det andet kan du skrive det sådan:

list.forEach( System.out::println );
Mest kompakt notation

Dette er nøjagtig den samme notation. Bemærk, at der ikke er nogen parentes efter println.

Her har vi den samme kode - et metodekald:

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

Tænk over det: vi ønskede at udføre en handling for hvert element i samlingen list. Hvis handlingen er et enkelt funktionskald (såsom println()), så giver det mening blot at videregive funktionen til metoden som en parameter.

Men hvordan forklarer vi compileren, at vi vil videregive metoden i stedet for at kalde den? For at gøre dette bruger vi i stedet for prikoperatoren to koloner før metodenavnet. Et enkelt kolon er allerede brugt til at angive den ternære operator.

Dette er den enkleste og mest kompakte notation.



3. Konstruktør

Metodereferencer med dobbelte koloner er meget praktiske, når vi arbejder med I/O-streams. Det vil du se lidt senere.

Lad os i mellemtiden tale om 3 populære måder at videregive en metodehenvisning på:

Reference til en metode til et objekt

For at videregive en reference til en metode til et objekt, skal du skrive noget som . Denne kode svarer til .object::method
x -> object.method(x)

Specialet thisog supervariablerne kan bruges som objektet.

Reference til en metode i en klasse

For at videregive en henvisning til en statisk metode, skal du skrive noget som . Denne kode bliver konverteret til kode somclass::methodx -> class.method(x);

Reference til en konstruktør

En konstruktør opfører sig på samme måde som en statisk klassemetode, så du kan også videregive en reference til en konstruktør. Sådan ser det ud :.class::new

For eksempel kan du komme uden om typesletning for samlinger og give toArray()metoden en reference til en konstruktør, der vil skabe det ønskede array:toArray(int[]::new);