Inferenz in Java 8 eingeben

30

Erfordert die Einführung der neuen Lambda-Notation (siehe z. B. diesen Artikel ) in Java 8 eine Art Typinferenz?

Wenn ja, wie wird sich das neue Typsystem auf die Java-Sprache insgesamt auswirken?

Giorgio
quelle

Antworten:

47

In der Antwort von Ratschenfreak und in seinem Kommentarthread gibt es einiges an falschen Informationen . Ich werde hier in einer Antwort antworten, da ein Kommentar zu klein ist. Da dies eine Antwort ist, werde ich auch versuchen, die ursprüngliche Frage zu beantworten. (Beachten Sie jedoch, dass ich kein Experte für Typsysteme bin.)

Erstens lauten die kurzen Antworten auf die ursprüngliche Frage "Ja" und "Nein". Ja, Java 8 weist erheblich mehr Typunterschiede auf als Java 7, und Nein, es gibt kein "neues" Typsystem in Java 8, obwohl es einige geringfügige Änderungen gibt .

Java 8 wird weiterhin statisch typisiert sein und die Dichotomie zwischen Klassen und Schnittstellen beibehalten. Es gibt keine neuen Typen wie Funktionstypen. Der Typ eines Lambda ist im Wesentlichen eine "funktionale Schnittstelle", die eine gewöhnliche Schnittstelle mit einer einzelnen abstrakten Methode ist.

Schnittstellen können jetzt Code in Form von Standardmethoden haben, das Modell der einfachen Vererbung von Klassen und der mehrfachen Vererbung von Schnittstellen bleibt jedoch dasselbe. Natürlich gibt es einige Anpassungen, z. B. Regeln für die Methodenauflösung bei Vorhandensein von Standardmethoden, aber die Grundlagen bleiben unverändert.

Jeder Typ, der durch Typinferenz abgeleitet wird, kann explizit ausgeschrieben werden. Um das Beispiel eines Ratschenfreaks zu verwenden ,

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

ist im Grunde Zucker für

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

So sparkleshy ‚s Aussage‚Typinferenz erfordert keine Erweiterung des Typsystems‘ist grundsätzlich richtig.

Um auf syntaktischen Zucker zurückzukommen, wiederhole ich meine Aussage, dass ein Lambda-Ausdruck für eine anonyme innere Klasse kein syntaktischer Zucker ist. Ratchet Freak erklärt , dass ein Lambda - Ausdruck in eine anonyme innere Klasse Instanziierung übersetzt wird, und Sparkleshy einfach bekräftigten , dass eine Lambda ist syntaktischer Zucker für eine anonyme innere Klasse, aber diese Aussagen sind falsch. Sie basieren wahrscheinlich auf veralteten Informationen. Frühe Lambda-Implementierungen haben Lambdas auf diese Weise implementiert, aber die Dinge haben sich geändert.

Lambda-Ausdrücke unterscheiden sich semantisch von inneren Klassen und werden anders als innere Klassen implementiert.

Lambda-Ausdrücke unterscheiden sich semantisch in einigen Punkten von inneren Klassen. Bei der Auswertung eines Lambda-Ausdrucks muss nicht jedes Mal eine neue Instanz erstellt werden. Sie haben auch unterschiedliche Erfassungssemantiken, zum Beispiel erfassen sie diese unterschiedlich. In einer inneren Klasse, dies ist die innere Klasseninstanz, wohingegen in einer Lambda, dies ist die umgebende Instanz. Folgendes berücksichtigen:

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

In einem aktuellen Lambda-Build für JDK 8 (ich habe b69 verwendet ) sieht die Ausgabe ungefähr so aus:

CaptureThis$1@113de03
outer

Darüber hinaus werden Lambda-Ausdrücke ganz anders als innere Klassen implementiert. Wenn Sie die disassemblierte Ausgabe vergleichen, werden Sie feststellen, dass der Code der inneren Klasse direkt zur Erstellung kompiliert und zu einem Konstruktor von CaptureThis $ 1 aufgerufen wird, wohingegen der Lambda-Ausdruck zu einer aufgerufenen dynamischen Anweisung kompiliert wird, die eine nicht spezifizierte Runnable through-Anweisung liefert. Eine vollständige Erklärung der Funktionsweise und des Grunds finden Sie in Brian Goetz 'JavaOne 2012-Vortrag Lambda: Ein Blick unter die Haube .

Stuart Marks
quelle
2
„. sie dies anders erfassen in einer inneren Klasse, das ist die innere Klasseninstanz, während in einem Lambda, das die umschließenden Instanz ist Folgendes zu beachten:“ kann nach wie vor mit syntaktischem Zucker erfolgen durch alle ersetzen thismitMyClass.this
Ratsche Freak
4
Alles, was über Assembler (und manchmal sogar das) hinausgeht, ist wohl syntaktischer Zucker. Lambdas sind jedoch kein syntaktischer Zucker für innere Klassen (mehr). Sie dienen einem ähnlichen Ziel und haben einige Ähnlichkeiten, aber unter der Haube sind sie (sichtbar) unterschiedlich.
Joachim Sauer
1
"Lambda-Ausdrücke unterscheiden sich semantisch von inneren Klassen, und sie werden anders als innere Klassen implementiert.": Vielen Dank für die sehr gute Erklärung (+1). Was mir immer noch nicht klar ist, ist, warum Lambdas nicht als syntaktischer Zucker für spezielle anonyme Klassen implementiert wurden oder was mit anderen Worten der Vorteil der zusätzlichen Komplexität ist, die durch die neue Semantik eingeführt wird? Welches Problem löst dies, das mit anonymen inneren Klassen nicht gelöst werden kann? (Aber ich muss noch auf den Link schauen, den Sie gepostet haben, vielleicht werde ich die Antwort dort finden.)
Giorgio
1
@Joachim Sauer: Ich würde syntaktischen Zucker als eine neue Syntax für eine existierende Semantik betrachten. Wenn eine neue Semantik eingeführt wird, kann man meines Erachtens nicht über syntaktischen Zucker sprechen. In diesem Sinne kann man meiner Meinung nach nicht behaupten, dass alles, was über Assembler hinausgeht, syntaktischer Zucker ist.
Giorgio
3
@Giorgio: In Bezug darauf, warum Lambda nicht nur syntaktischer Zucker für anonyme innere Klassen ist, stellte sich heraus, dass es eine große Diskussion darüber gab. Diese Mail von Brian Goetz fasst die Entscheidung zusammen: mail.openjdk.java.net/pipermail/lambda-dev/2011-August/… . TL; DR lässt die Tür für zukünftige Entwicklungen offen und wir erzielen heute eine bessere Leistung. Goetz beantwortet tatsächlich eine verwandte Frage: Sind Lambdas Objekte? Aber wenn die Antwort "Nein" oder "Vielleicht" lautet, bedeutet dies, dass sie für die inneren Klassen kein Zucker sein können.
Stuart Marks