Der Doppelpunktoperator in Java 8

1. Übersicht

In diesem kurzen Artikel werden wir den Doppelpunktoperator ( ::) in Java 8 diskutieren und die Szenarien durchgehen, in denen der Operator verwendet werden kann.

2. Von Lambdas zum Doppelpunktoperator

Mit Lambdas-Ausdrücken haben wir gesehen, dass Code sehr präzise werden kann.

Um beispielsweise einen Komparator zu erstellen , reicht die folgende Syntax aus:

Comparator c = (Computer c1, Computer c2) -> c1.getAge().compareTo(c2.getAge()); 

Dann mit Typinferenz:

Comparator c = (c1, c2) -> c1.getAge().compareTo(c2.getAge());

Aber können wir den obigen Code noch ausdrucksvoller und lesbarer machen? Werfen wir einen Blick:

Comparator c = Comparator.comparing(Computer::getAge); 

Wir haben den Operator :: als Abkürzung für Lambdas verwendet, die eine bestimmte Methode aufrufen - nach Namen. Und das Ergebnis ist natürlich eine noch besser lesbare Syntax.

3. Wie funktioniert es?

Ganz einfach ausgedrückt, wenn wir eine Methodenreferenz verwenden - die Zielreferenz wird vor dem Trennzeichen :: platziert und der Name der Methode wird danach angegeben.

Zum Beispiel:

Computer::getAge;

Wir sehen uns einen Methodenverweis auf die in der Computerklasse definierte Methode getAge an .

Wir können dann mit dieser Funktion arbeiten:

Function getAge = Computer::getAge; Integer computerAge = getAge.apply(c1); 

Beachten Sie, dass wir auf die Funktion verweisen und sie dann auf die richtige Art von Argument anwenden.

4. Methodenreferenzen

Wir können diesen Operator in einigen Szenarien gut nutzen.

4.1. Eine statische Methode

Zunächst verwenden wir eine statische Dienstprogrammmethode :

List inventory = Arrays.asList( new Computer( 2015, "white", 35), new Computer(2009, "black", 65)); inventory.forEach(ComputerUtils::repair); 

4.2. Eine Instanzmethode eines vorhandenen Objekts

Schauen wir uns als nächstes ein interessantes Szenario an - das Verweisen auf eine Methode einer vorhandenen Objektinstanz .

Wir werden die Variable System verwenden . out - ein Objekt vom Typ Print welche die Abstützungen Druckverfahren:

Computer c1 = new Computer(2015, "white"); Computer c2 = new Computer(2009, "black"); Computer c3 = new Computer(2014, "black"); Arrays.asList(c1, c2, c3).forEach(System.out::print); 

4.3. Eine Instanzmethode eines beliebigen Objekts eines bestimmten Typs

Computer c1 = new Computer(2015, "white", 100); Computer c2 = new MacbookPro(2009, "black", 100); List inventory = Arrays.asList(c1, c2); inventory.forEach(Computer::turnOnPc); 

Wie Sie sehen, verweisen wir auf die turnOnPc- Methode nicht auf eine bestimmte Instanz, sondern auf den Typ selbst.

In Zeile 4 wird für jedes Inventarobjekt die Instanzmethode turnOnPc aufgerufen .

Und das bedeutet natürlich, dass - für c1 die Methode turnOnPc auf der Computerinstanz und für c2 auf der MacbookPro- Instanz aufgerufen wird .

4.4. Eine Supermethode eines bestimmten Objekts

Angenommen, Sie haben die folgende Methode in der Computer- Superklasse:

public Double calculateValue(Double initialValue) { return initialValue/1.50; } 

und diese in der MacbookPro- Unterklasse:

@Override public Double calculateValue(Double initialValue){ Function function = super::calculateValue; Double pcValue = function.apply(initialValue); return pcValue + (initialValue/10) ; } 

Ein Aufruf der berechneValue- Methode auf einer MacbookPro- Instanz:

macbookPro.calculateValue(999.99); 

wird auch einen Aufruf zum Berechnen des Wertes in der Computer- Superklasse erzeugen .

5. Konstruktorreferenzen

5.1. Erstellen Sie eine neue Instanz

Das Referenzieren eines Konstruktors zum Instanziieren eines Objekts kann ganz einfach sein:

@FunctionalInterface public interface InterfaceComputer { Computer create(); } InterfaceComputer c = Computer::new; Computer computer = c.create(); 

Was ist, wenn Sie zwei Parameter in einem Konstruktor haben?

BiFunction c4Function = Computer::new; Computer c4 = c4Function.apply(2013, "white"); 

Wenn die Parameter drei oder mehr sind, müssen Sie eine neue Funktionsschnittstelle definieren:

@FunctionalInterface interface TriFunction { R apply(A a, B b, C c); default  TriFunction andThen( Function after) { Objects.requireNonNull(after); return (A a, B b, C c) -> after.apply(apply(a, b, c)); } } 

Initialisieren Sie dann Ihr Objekt:

TriFunction  c6Function = Computer::new; Computer c3 = c6Function.apply(2008, "black", 90); 

5.2. Erstellen Sie ein Array

Lassen Sie uns abschließend sehen, wie Sie ein Array von Computerobjekten mit fünf Elementen erstellen :

Function  computerCreator = Computer[]::new; Computer[] computerArray = computerCreator.apply(5); 

6. Fazit

Wie wir sehen, wird der in Java 8 eingeführte Doppelpunktoperator in einigen Szenarien und insbesondere in Verbindung mit Streams sehr nützlich sein.

Es ist auch sehr wichtig, sich die funktionalen Schnittstellen anzusehen, um besser zu verstehen, was hinter den Kulissen passiert.

Der vollständige Quellcode für das Beispiel ist in diesem GitHub-Projekt verfügbar. Dies ist ein Maven- und Eclipse-Projekt, damit es importiert und unverändert verwendet werden kann.