Methodenreferenzen in Java

1. Übersicht

Eine der willkommensten Änderungen in Java 8 war die Einführung von Lambda-Ausdrücken, da wir auf anonyme Klassen verzichten können, wodurch der Code für das Boilerplate erheblich reduziert und die Lesbarkeit verbessert wird.

Methodenreferenzen sind eine spezielle Art von Lambda-Ausdrücken . Sie werden häufig verwendet, um einfache Lambda-Ausdrücke zu erstellen, indem auf vorhandene Methoden verwiesen wird.

Es gibt vier Arten von Methodenreferenzen:

  • Statische Methoden
  • Instanzmethoden bestimmter Objekte
  • Instanzmethoden eines beliebigen Objekts eines bestimmten Typs
  • Konstrukteur

In diesem Tutorial werden Methodenreferenzen in Java untersucht.

2. Verweis auf eine statische Methode

Wir beginnen mit einem sehr einfachen Beispiel, bei dem eine Liste von Zeichenfolgen groß geschrieben und gedruckt wird :

List messages = Arrays.asList("hello", "baeldung", "readers!");

Wir können dies erreichen, indem wir einen einfachen Lambda-Ausdruck nutzen, der die StringUtils.capitalize () -Methode direkt aufruft :

messages.forEach(word -> StringUtils.capitalize(word));

Oder wir können eine Methodenreferenz verwenden, um einfach auf die statische Großschreibungsmethode zu verweisen :

messages.forEach(StringUtils::capitalize);

Beachten Sie, dass Methodenreferenzen immer den Operator :: verwenden .

3. Verweis auf eine Instanzmethode eines bestimmten Objekts

Um diese Art von Methodenreferenz zu demonstrieren, betrachten wir zwei Klassen:

public class Bicycle { private String brand; private Integer frameSize; // standard constructor, getters and setters } public class BicycleComparator implements Comparator { @Override public int compare(Bicycle a, Bicycle b) { return a.getFrameSize().compareTo(b.getFrameSize()); } }

Erstellen wir ein BicycleComparator- Objekt, um die Fahrradrahmengrößen zu vergleichen:

BicycleComparator bikeFrameSizeComparator = new BicycleComparator();

Wir könnten einen Lambda-Ausdruck verwenden, um Fahrräder nach Rahmengröße zu sortieren, aber wir müssten zum Vergleich zwei Fahrräder angeben:

createBicyclesList().stream() .sorted((a, b) -> bikeFrameSizeComparator.compare(a, b));

Stattdessen können wir eine Methodenreferenz verwenden, damit der Compiler-Handle-Parameter für uns übergeben wird:

createBicyclesList().stream() .sorted(bikeFrameSizeComparator::compare);

Die Methodenreferenz ist viel sauberer und lesbarer, da der Code unsere Absicht deutlich zeigt.

4. Verweis auf eine Instanzmethode eines beliebigen Objekts eines bestimmten Typs

Diese Art der Methodenreferenz ähnelt dem vorherigen Beispiel, muss jedoch kein benutzerdefiniertes Objekt erstellen, um den Vergleich durchzuführen.

Erstellen wir eine Ganzzahlliste , die wir sortieren möchten:

List numbers = Arrays.asList(5, 3, 50, 24, 40, 2, 9, 18);

Wenn wir einen klassischen Lambda-Ausdruck verwenden, müssen beide Parameter explizit übergeben werden, während die Verwendung einer Methodenreferenz viel einfacher ist:

numbers.stream() .sorted((a, b) -> a.compareTo(b)); numbers.stream() .sorted(Integer::compareTo);

Obwohl es sich immer noch um einen Einzeiler handelt, ist die Methodenreferenz viel einfacher zu lesen und zu verstehen.

5. Verweis auf einen Konstruktor

Wir können einen Konstruktor genauso referenzieren, wie wir in unserem ersten Beispiel auf eine statische Methode verwiesen haben. Der einzige Unterschied besteht darin, dass wir das neue Schlüsselwort verwenden.

Erstellen wir ein Fahrradarray aus einer String- Liste mit verschiedenen Marken:

List bikeBrands = Arrays.asList("Giant", "Scott", "Trek", "GT");

Zuerst fügen wir unserer Fahrradklasse einen neuen Konstruktor hinzu :

public Bicycle(String brand) { this.brand = brand; this.frameSize = 0; } 

Als Nächstes verwenden wir unseren neuen Konstruktor aus einer Methodenreferenz und erstellen aus der ursprünglichen String- Liste ein Bicycle- Array :

bikeBrands.stream() .map(Bicycle::new) .toArray(Bicycle[]::new); 

Beachten Sie, wie wir sowohl Bicycle- als auch Array- Konstruktoren mithilfe einer Methodenreferenz aufgerufen haben , um unserem Code ein viel präziseres und klareres Erscheinungsbild zu verleihen.

6. Zusätzliche Beispiele und Einschränkungen

Wie wir bisher gesehen haben, sind Methodenreferenzen eine großartige Möglichkeit, unseren Code und unsere Absichten sehr klar und lesbar zu machen. Wir können sie jedoch nicht verwenden, um alle Arten von Lambda-Ausdrücken zu ersetzen, da sie einige Einschränkungen aufweisen.

Ihre Hauptbeschränkung ergibt sich aus ihrer größten Stärke: Die Ausgabe des vorherigen Ausdrucks muss mit den Eingabeparametern der referenzierten Methodensignatur übereinstimmen .

Sehen wir uns ein Beispiel für diese Einschränkung an:

createBicyclesList().forEach(b -> System.out.printf( "Bike brand is '%s' and frame size is '%d'%n", b.getBrand(), b.getFrameSize()));

Dieser einfache Fall kann nicht mit einer Methodenreferenz ausgedrückt werden, da für die printf- Methode in unserem Fall 3 Parameter erforderlich sind und bei Verwendung von createBicyclesList (). ForEach () nur die Methodenreferenz einen Parameter (das Bicycle- Objekt) ableiten kann .

Lassen Sie uns abschließend untersuchen, wie Sie eine No-Operation-Funktion erstellen, auf die aus einem Lambda-Ausdruck verwiesen werden kann.

In diesem Fall möchten wir einen Lambda-Ausdruck ohne Verwendung seiner Parameter verwenden.

Erstellen wir zunächst die Methode doNothingAtAll :

private static  void doNothingAtAll(Object... o) { }

Da es sich um eine varargs-Methode handelt, funktioniert sie in jedem Lambda-Ausdruck, unabhängig vom referenzierten Objekt oder der Anzahl der abgeleiteten Parameter.

Lassen Sie es uns jetzt in Aktion sehen:

createBicyclesList() .forEach((o) -> MethodReferenceExamples.doNothingAtAll(o)); 

7. Fazit

In diesem kurzen Tutorial haben wir gelernt, welche Methodenreferenzen in Java vorhanden sind und wie sie zum Ersetzen von Lambda-Ausdrücken verwendet werden, um die Lesbarkeit zu verbessern und die Absicht des Programmierers zu verdeutlichen.

Der gesamte in diesem Artikel vorgestellte Code ist auf GitHub verfügbar.