CodeGym /Kurse /JAVA 25 SELF /Method References (::): Methodenreferenzen

Method References (::): Methodenreferenzen

JAVA 25 SELF
Level 21, Lektion 1
Verfügbar

1. Einführung

Method reference (auf Deutsch – Methodenreferenz) ist eine spezielle Syntax in Java, die es erlaubt, eine bereits existierende Methode (oder einen Konstruktor) als Implementierung eines funktionalen Interfaces zu übergeben. Eine Methode kann dort „weitergereicht“ werden, wo ein Lambda-Ausdruck erwartet wird, sofern die Signaturen übereinstimmen.

Syntax:

Class::method
object::method
Class::new

Wenn eine Lambda so etwas wie eine kleine Funktion „on the fly“ ist, dann bedeutet eine Methodenreferenz einfach: „gib die bereits vorhandene Methode weiter“. Das ist wie statt des Abschreibens eines Rezepts den Link auf die Rezeptseite zu geben.

Anschauliches Beispiel

Stattdessen:

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

Kann man so schreiben:

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

Sieht doch kompakt aus, oder?

2. Arten von Methodenreferenzen

Es gibt vier Hauptformen von Methodenreferenzen. Das sind sie – mehr braucht man nicht.

Verweis auf eine statische Methode

Syntax: Class::staticMethod

Beispiel:

Function<Integer, String> intToString = String::valueOf;
System.out.println(intToString.apply(123)); // "123"

Dasselbe mit einer Lambda:

Function<Integer, String> intToString = i -> String.valueOf(i);

Verweis auf eine Instanzmethode eines Objekts

Syntax: object::method

Beispiel:

PrintStream printer = System.out;
Consumer<String> consumer = printer::println;
consumer.accept("Hallo, Welt!");

Entspricht einer Lambda:

Consumer<String> consumer = s -> printer.println(s);

Verweis auf eine Instanzmethode einer Klasse

Syntax: Class::method

Hier wird der erste Parameter des funktionalen Interfaces zu dem Objekt, auf dem die Methode aufgerufen wird.

Beispiel:

Function<String, Integer> stringLength = String::length;
System.out.println(stringLength.apply("Java")); // 4

Hier wird String::length zu einer Funktion: (String s) -> s.length()

Verweis auf einen Konstruktor

Syntax: Class::new

Beispiel:

Supplier<ArrayList<String>> listSupplier = ArrayList::new;
ArrayList<String> list = listSupplier.get();

Entspricht einer Lambda:

Supplier<ArrayList<String>> listSupplier = () -> new ArrayList<>();

3. Wann sollte man Methodenreferenzen verwenden?

Methodenreferenzen sind praktisch, wenn eine Lambda lediglich eine bereits existierende Methode ohne zusätzliche Logik aufruft – so wird der Code kürzer und besser lesbar.

Beispiel: Liste sortieren

Stattdessen:

List<String> names = Arrays.asList("John", "Peter", "Anna");
names.sort((a, b) -> a.compareToIgnoreCase(b));

Kann man so schreiben:

names.sort(String::compareToIgnoreCase);

Beispiel: Kollektionen verarbeiten

Statt:

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

Noch kürzer:

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

Beispiel: Elemente transformieren

Statt:

List<String> numbers = Arrays.asList("1", "2", "3");
List<Integer> ints = numbers.stream()
    .map(s -> Integer.parseInt(s))
    .collect(Collectors.toList());

Möglich ist auch:

List<Integer> ints = numbers.stream()
    .map(Integer::parseInt)
    .collect(Collectors.toList());

Mehr über das Stream API und die Hilfsklasse Collectors erfahren Sie auf Level 30 :P

4. Vergleich: Methodenreferenz und Lambda-Ausdruck

Äquivalenz

Methodenreferenz und Lambda-Ausdruck sind oft austauschbar. Beide implementieren ein funktionales Interface, wenn die Signaturen übereinstimmen.

Beispiel:

Consumer<String> c1 = s -> System.out.println(s);
Consumer<String> c2 = System.out::println;

Wann ist eine Methodenreferenz sinnvoller?

  • Wenn die Lambda lediglich eine existierende Methode ohne zusätzliche Logik aufruft.
  • Zur Steigerung der Lesbarkeit, insbesondere in langen Aufrufketten.
  • Wenn man explizit zeigen möchte: „hier wird einfach nur eine Methode aufgerufen“.

Wann ist eine Methodenreferenz ungeeignet?

  • Wenn zusätzliche Logik nötig ist (Validierung, Bedingungen, Fehlerbehandlung).
  • Wenn Parameter vor dem Methodenaufruf transformiert werden müssen.

Beispiel:

list.forEach(s -> {
    if (s != null) System.out.println(s);
});
// Hier ist eine Methodenreferenz nicht geeignet, nur eine Lambda.

5. Praxis: Lambdas mit Methodenreferenzen umschreiben

Beispiel 1: Tiernamen ausgeben

List<String> animals = Arrays.asList("Katze", "Hund", "Papagei");
animals.forEach(animal -> System.out.println(animal));

Wird zu:

animals.forEach(System.out::println);

Beispiel 2: Strings in Zahlen umwandeln

List<String> numbers = Arrays.asList("10", "20", "30");
List<Integer> ints = numbers.stream()
    .map(s -> Integer.parseInt(s))
    .collect(Collectors.toList());

Wird zu:

List<Integer> ints = numbers.stream()
    .map(Integer::parseInt)
    .collect(Collectors.toList());

Beispiel 3: Objekte nach Namen sortieren

List<Animal> animalList = ...;
animalList.sort((a, b) -> a.getName().compareTo(b.getName()));

Wird zu:

animalList.sort(Comparator.comparing(Animal::getName));

Hier ist Animal::getName ein Verweis auf eine Instanzmethode der Klasse.

Beispiel 4: Objekte über einen Konstruktor erstellen

Supplier<Dog> dogFactory = () -> new Dog();
Dog dog = dogFactory.get();

Wird zu:

Supplier<Dog> dogFactory = Dog::new;
Dog dog = dogFactory.get();

6. Wie funktioniert die Signaturzuordnung?

Eine Methodenreferenz kann nur verwendet werden, wenn die Methodensignatur mit der des abstrakten Methodenmembers des funktionalen Interfaces übereinstimmt.

@FunctionalInterface
interface IntToString {
    String convert(int value);
}

public class Demo {
    public static String intToHex(int value) {
        return Integer.toHexString(value);
    }

    public static void main(String[] args) {
        IntToString converter = Demo::intToHex;
        System.out.println(converter.convert(255)); // ff
    }
}

Hier passt Demo::intToHex, weil es ein int entgegennimmt und ein String zurückgibt.

7. Methodenreferenzen und Konstruktoren mit Parametern

Wenn ein Konstruktor Parameter entgegennimmt, kann man dennoch eine Methodenreferenz verwenden – bei übereinstimmenden Signaturen.

@FunctionalInterface
interface AnimalFactory {
    Animal create(String name);
}

class Animal {
    private String name;
    public Animal(String name) { this.name = name; }
    public String getName() { return name; }
}

AnimalFactory factory = Animal::new;
Animal cat = factory.create("Felix");
System.out.println(cat.getName()); // Felix

8. Typische Fehler bei der Verwendung von Methodenreferenzen

Fehler Nr. 1: Abweichende Signaturen.
Wenn die Methodensignatur nicht mit der des abstrakten Interface-Methods übereinstimmt, meldet der Compiler einen Fehler. Beispielsweise erwartet das Interface zwei Parameter, die Referenz zeigt jedoch auf eine Methode mit nur einem Parameter.

Fehler Nr. 2: Versuch, auf eine Instanzmethode der Klasse ohne Objekt zu verweisen.
Wenn Sie die Form Class::method verwenden, wird der erste Parameter des Interfaces zum aufrufenden Objekt. Wenn Anzahl oder Reihenfolge der Parameter verwechselt werden, kommt es zu einem Zuordnungsfehler.

Fehler Nr. 3: Einsatz einer Methodenreferenz, wo zusätzliche Logik nötig ist.
Wenn Bedingungen, Logging oder Ausnahmebehandlung erforderlich sind, verwenden Sie eine Lambda und keine Methodenreferenz.

Fehler Nr. 4: Verweise auf überladene Methoden.
Wenn eine Klasse mehrere Methoden mit demselben Namen hat, kann der Compiler unter Umständen nicht entscheiden, welche gewählt werden soll. Manchmal hilft die explizite Angabe des Typs des funktionalen Interfaces.

Fehler Nr. 5: Verwendung eines Verweises auf eine Instanzmethode ohne Objekt.
Zum Beispiel funktioniert String::toUpperCase in map korrekt, weil der erste Parameter das Objekt String selbst ist. Außerhalb eines passenden Kontexts, in dem eine statische Methode erwartet wird, führt dies jedoch zu einem Fehler.

1
Aufgabe
JAVA 25 SELF, Level 21, Lektion 1
Gesperrt
Konverter für Geräte-IDs 📟
Konverter für Geräte-IDs 📟
1
Aufgabe
JAVA 25 SELF, Level 21, Lektion 1
Gesperrt
Individuelles Logging-System 📝
Individuelles Logging-System 📝
1
Aufgabe
JAVA 25 SELF, Level 21, Lektion 1
Gesperrt
Organisation des Lagerbestands 🍎🍌🍐
Organisation des Lagerbestands 🍎🍌🍐
1
Aufgabe
JAVA 25 SELF, Level 21, Lektion 1
Gesperrt
Fabrik für virtuelle Haustiere 🐾
Fabrik für virtuelle Haustiere 🐾
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION