1. Funktionsmethoden

Wenn eine Schnittstelle nur über eine Methode verfügt , kann einer Variablen dieses Schnittstellentyps ein durch einen Lambda-Ausdruck (Lambda-Funktion) gegebener Wert zugewiesen werden. Solche Schnittstellen wurden als funktionale Schnittstellen bekannt (nachdem Java Unterstützung für Lambda-Funktionen hinzugefügt hatte).

Beispielsweise verfügt Java über die Consumer<Type>Schnittstelle, die über die accept(Type obj)Methode verfügt. Warum wird diese Schnittstelle benötigt?

In Java 8 verfügen Sammlungen über eine forEach()Methode, mit der Sie für jedes Element der Sammlung eine Aktion ausführen können . Und hier wird die funktionale Schnittstelle verwendet, um die Aktion an die Methode zu übergeben. Consumer<T>forEach()

So können Sie alle Elemente einer Sammlung anzeigen :

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

list.forEach( (s) -> System.out.println(s) );
Alle Elemente einer Sammlung anzeigen (mithilfe eines Lambda-Ausdrucks)

Der Compiler konvertiert den obigen Code in den folgenden Code:

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));
   }
});
Alle Elemente einer Sammlung anzeigen (mithilfe einer anonymen Klasse)

Die erste Version ist definitiv kürzer als die zweite. Und während Code mit Lambda-Ausdrücken schwer zu lesen ist, ist Code mit anonymen inneren Klassen manchmal sogar noch schwieriger zu lesen.



2. Methodenreferenz

Unser Lambda-Ausdruckscode kann jedoch noch kürzer geschrieben werden.

Zunächst können Sie die Klammern um den sParameter weglassen:

list.forEach( (s) -> System.out.println(s) );
Vor
list.forEach( s -> System.out.println(s) );
Nach

Dies ist nur möglich, wenn ein Parameter vorhanden ist . Wenn mehrere Parameter vorhanden sind , müssen Sie Klammern verwenden .

Und zweitens können Sie es so schreiben:

list.forEach( System.out::println );
Kompakteste Notation

Dies ist genau die gleiche Notation. Beachten Sie, dass nach dem keine Klammern stehen println.

Hier haben wir den gleichen Code – einen Methodenaufruf:

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

Denken Sie darüber nach: Wir wollten für jedes Element der Sammlung eine Aktion ausführen list. Handelt es sich bei der Aktion um einen einzelnen Funktionsaufruf (z. B. println()), dann ist es sinnvoll, die Funktion einfach als Parameter an die Methode zu übergeben.

Aber wie erklären wir dem Compiler, dass wir die Methode übergeben statt aufrufen wollen? Dazu verwenden wir anstelle des Punktoperators zwei Doppelpunkte vor dem Methodennamen. Zur Angabe des ternären Operators wird bereits ein einzelner Doppelpunkt verwendet.

Dies ist die einfachste und kompakteste Notation.



3. Konstrukteur

Methodenreferenzen mit Doppelpunkten sind sehr praktisch, wenn wir mit I/O-Streams arbeiten. Das werden Sie etwas später sehen.

Lassen Sie uns in der Zwischenzeit über drei beliebte Möglichkeiten zur Übergabe einer Methodenreferenz sprechen:

Verweis auf eine Methode eines Objekts

Um einen Verweis auf eine Methode eines Objekts zu übergeben, müssen Sie etwas wie schreiben . Dieser Code entspricht .object::method
x -> object.method(x)

Als Objekt können die Sonder- thisund Variablen verwendet werden.super

Verweis auf eine Methode einer Klasse

Um einen Verweis auf eine statische Methode zu übergeben, müssen Sie etwas wie schreiben . Dieser Code wird in Code umgewandeltclass::methodx -> class.method(x);

Verweis auf einen Konstruktor

Ein Konstruktor verhält sich ähnlich wie eine statische Klassenmethode, Sie können also auch eine Referenz an einen Konstruktor übergeben. So sieht es aus: .class::new

Sie können beispielsweise das Löschen von Typen für Sammlungen umgehen und der toArray()Methode einen Verweis auf einen Konstruktor übergeben, der das gewünschte Array erstellt:toArray(int[]::new);