1135 Stimmen

:: (Doppelpunkt Doppelpunkt) Operator in Java 8

Ich habe den Java 8-Quellcode erkundet und diesen bestimmten Codeteil als sehr überraschend gefunden:

// In IntPipeline.java definiert
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
    return evaluate(ReduceOps.makeInt(op));
}

@Override
public final OptionalInt max() {
    return reduce(Math::max); // Dies ist die überraschende Zeile
}

// In Math.java definiert
public static int max(int a, int b) {
    return (a >= b) ? a : b;
}

Ist Math::max ähnlich wie ein Methodenzeiger?
Wie wird eine normale static-Methode in einen IntBinaryOperator umgewandelt?

24voto

David Punkte 18989

Dies ist eine Methodenreferenz in Java 8. Die Oracle-Dokumentation finden Sie hier.

Wie in der Dokumentation angegeben...

Die Methodenreferenz Person::compareByAge ist eine Referenz auf eine statische Methode.

Das folgende ist ein Beispiel für eine Referenz auf eine Instanzmethode eines bestimmten Objekts:

class ComparisonProvider {
    public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }

    public int compareByAge(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}

ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName); 

Die Methodenreferenz myComparisonProvider::compareByName ruft die Methode compareByName auf, die Teil des Objekts myComparisonProvider ist. Die JRE leitet die Methodentyp-Argumente ab, die in diesem Fall (Person, Person) sind.

12voto

Vaibhav9518 Punkte 149

Der :: Operator wurde in Java 8 für Methodenreferenzen eingeführt. Eine Methodenreferenz ist die verkürzte Syntax für einen Lambda-Ausdruck, der nur eine Methode ausführt. Hier ist die allgemeine Syntax einer Methodenreferenz:

Object :: methodName

Wir wissen, dass wir Lambda-Ausdrücke anstelle einer anonymen Klasse verwenden können. Manchmal ist der Lambda-Ausdruck jedoch wirklich nur ein Aufruf einer Methode, zum Beispiel:

Consumer c = s -> System.out.println(s);

Um den Code klarer zu machen, können Sie diesen Lambda-Ausdruck in eine Methodenreferenz umwandeln:

Consumer c = System.out::println;

8voto

Nertan Lucian Punkte 352

Also sehe ich hier tonnenweise Antworten, die ehrlich gesagt überkompliziert sind, und das ist noch untertrieben.

Die Antwort ist ziemlich einfach: **:: wird als Methodenreferenzen bezeichnet. In Methodenreferenzen findest du alle Informationen, wenn du zur Tabelle scrollst.


Lass uns jetzt einen kurzen Blick darauf werfen, was eine Methodenreferenz ist:

A::b ersetzt gewissermaßen den folgenden inline Lambda-Ausdruck: (Parameter ...) -> A.b(Parameter ...)

Um das mit deinen Fragen in Verbindung zu bringen, ist es erforderlich, ein Java-Lambda-Ausdruck zu verstehen. Was nicht schwer ist.

Ein inline Lambda-Ausdruck ähnelt einem definierten funktionalen Interface (das ist ein Interface, das genau eine Methode hat).

Lass uns kurz betrachten, was ich meine:

InterfaceX f = (x) -> x*x;

InterfaceX muss ein funktionales Interface sein. Jedes funktionale Interface, das Einzige, worauf es dem Compiler bei InterfaceX ankommt, ist, dass du das Format definierst:

InterfaceX kann eines dieser sein:

interface InterfaceX
{
    public Integer callMe(Integer x);
}

Oder dieses:

interface InterfaceX
{
    public Double callMe(Integer x);
}

Oder generischer:

interface InterfaceX
{
    public T callMe(U x);
}

Lasst uns den ersten vorgestellten Fall und den inline Lambda-Ausdruck, den wir zuvor definiert haben, betrachten.

Vor Java 8 könntest du es ähnlich wie folgt definiert haben:

 InterfaceX o = new InterfaceX(){
                        public int callMe(int x)
                        {
                            return x*x;
                        }
                    };

Funktional ist es dasselbe. Der Unterschied liegt eher darin, wie der Compiler dies wahrnimmt.

Nachdem wir uns den inline Lambda-Ausdruck angesehen haben, kehren wir zum Methodenreferenz (::) zurück. Nehmen wir an, du hast eine Klasse wie diese:

class Q {
    public static int anyFunction(int x)
    {
        return x + 5;
    }
}

Da die Methode anyFunction die gleichen Typen wie InterfaceX callMe hat, können wir diese beiden mit einer Methodenreferenz gleichsetzen.

Wir können es so schreiben:

InterfaceX o =  Q::anyFunction;

Und das ist äquivalent zu diesem:

InterfaceX o = (x) -> Q.anyFunction(x);

Eine coole Sache und ein Vorteil von Methodenreferenzen ist, dass sie zuerst, bis du sie Variablen zuweist, typenlos sind. Du kannst sie also als Parameter an jedes ähnlich aussehende (hat die gleichen definierten Typen) funktionale Interface übergeben. Genau das passiert in deinem Fall.

3voto

Sonu Punkte 602

Das :: wird als Methodenreferenz bezeichnet. Angenommen, wir möchten eine calculatePrice-Methode der Klasse Purchase aufrufen. Dann können wir es so schreiben:

Purchase::calculatePrice

Es kann auch als Kurzform für das Schreiben des Lambda-Ausdrucks angesehen werden, da Methodenreferenzen in Lambda-Ausdrücke umgewandelt werden.

3voto

Houssem Badri Punkte 2265

Ich fand diese Quelle sehr interessant.

Tatsächlich ist es das Lambda, das zu einem Doppelpunkt wird. Der Doppelpunkt ist lesbarer.

Wir folgen diesen Schritten:

Schritt 1

// Wir erstellen einen Vergleicher für zwei Personen
Comparator c = (Person p1, Person p2) -> p1.getAge().compareTo(p2.getAge());

Schritt 2

// Wir verwenden die Interferenz
Comparator c = (p1, p2) -> p1.getAge().compareTo(p2.getAge());

Schritt 3

// Die Magie der Verwendung von Methodenreferenz
Comparator c = Comparator.comparing(Person::getAge);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X