Ich habe mich immer gefragt, warum Java keine Typinferenz ausführt, da die Sprache so ist, wie sie ist, und die VM sehr ausgereift ist. Googles Go ist ein Beispiel für eine Sprache mit hervorragenden Tippfehlern und reduziert den Aufwand für die Eingabe. Gibt es einen besonderen Grund dafür, dass diese Funktion nicht Teil von Java ist?
44
Antworten:
Aus technischer Sicht verfügt Java bei der Verwendung von Generika über eine Typinferenz . Mit einer generischen Methode wie
Der Compiler wird das analysieren und verstehen, wenn Sie schreiben
Für den ersten Aufruf wird eine Zeichenfolge und für den zweiten Aufruf eine Ganzzahl zurückgegeben, basierend auf dem, was als Argument eingegeben wurde. Als Ergebnis erhalten Sie die richtige Überprüfung zur Kompilierungszeit. Darüber hinaus kann man in Java 7 zusätzliche Typinferenzen erhalten, wenn Generika wie diese instanziiert werden
Java ist so nett, die leeren spitzen Klammern für uns auszufüllen. Warum unterstützt Java keine Typinferenz als Teil der Variablenzuweisung? Zu einem bestimmten Zeitpunkt gab es eine RFE für die Typinferenzierung in Variablendeklarationen, die jedoch geschlossen wurde, weil "Nicht behoben"
Der Beitragende, der dies schloss, bemerkte auch, dass es sich einfach "un-java-like" anfühlt, dem ich zustimmen kann. Javas Ausführlichkeit kann sowohl ein Segen als auch ein Fluch sein, aber sie macht die Sprache zu dem, was sie ist.
Natürlich war diese besondere RFE nicht das Ende dieser Unterhaltung. In Java 7 wurde diese Funktion erneut in Betracht gezogen , und einige Testimplementierungen wurden erstellt, darunter eine von James Gosling. Auch dieses Feature wurde letztendlich abgeschossen.
Mit der Veröffentlichung von Java 8 erhalten wir jetzt Typinferenz als Teil von Lambdas als solche:
Der Java-Compiler kann die Methode
Collections#sort(List<T>, Comparator<? super T>)
und dann die Schnittstelle vonComparator#compare(T o1, T o2)
und bestimmen,first
undsecond
sollteString
es dem Programmierer daher ermöglichen, auf das erneute Eingeben des Typs im Lambda-Ausdruck zu verzichten.quelle
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns
- ja, wenn ja,HashMap<String, Integer> map = foo.getMap()
stimme ich zu - in C # verwende ichvar
in solchen Fällen normalerweise nicht , obwohl ich könnte. Aber dieses Argument hält nicht Wasser, wenn es istHashMap<String, Integer> map = new HashMap<String, Integer>()
. Dies ist eine echte Redundanz, und ich sehe keinen Vorteil darin, den Typnamen zweimal schreiben zu müssen. Und wie ich hier von einem Compiler-Crosscheck profitieren würde, verstehe ich überhaupt nicht.var
in Java.Humans benefit from the redundancy
ist die wirkliche Antwort auf die aktuelle Frage, denn jede Begründung, die ich gelesen habe, scheint eine unbegründete und lächerliche Entschuldigung von Java-Designern zu sein: Sowohl C # als auch C ++ haben die Funktion, C # - und C ++ - Designer sind nicht weniger kompetent als Java ist, und jeder ist glücklich damit. Was würde dazu führen, dass sich Java-Entwickler von C # - oder C ++ - Entwicklern unterscheiden? Deshalb stimme ich @KonradMorawski zu: "So wird es hier gemacht" scheint wieder der wahre Grund dafür zu sein.Zunächst einmal hat die Typinferenz nichts mit der Laufzeit zu tun, unabhängig davon, ob es sich bei dieser Laufzeit um eine 30 Jahre alte CPU oder eine VM handelt, die so neu ist, dass die Bits immer noch glänzend sind. Alles dreht sich um den Compiler.
Das heißt, es ist für Generika zulässig. Der Grund, warum es für nicht generische Typen nicht zulässig ist, scheint in der Philosophie zu liegen - nichts hindert die Designer daran, es hinzuzufügen.
Update: Offenbar wird es von Java 10 unterstützt - http://openjdk.java.net/jeps/286
quelle
Soweit ich weiß, war die Typinferenz zu Beginn der neunziger Jahre bei Java-Entwicklern unter den gängigen Sprachen nicht so beliebt (aber es war bereits ein sehr bekanntes Konzept, z. B. in ML). Daher kann ich mir vorstellen, dass Typinferenz wahrscheinlich nicht unterstützt wurde, da Java auf Programmierer abzielte, die aus C ++, Pascal oder anderen Mainstream-Sprachen stammten, die es nicht hatten (Prinzip der geringsten Überraschung).
Eines der Entwurfsprinzipien von Java besteht darin, Dinge explizit zu schreiben, um sicherzustellen, dass Programmierer und Compiler den Code gleich verstehen: Durch das Duplizieren von Informationen wird die Wahrscheinlichkeit von Fehlern verringert. Es mag natürlich eine Geschmackssache sein, ob die Eingabe einiger weiterer Zeichen die zusätzliche Sicherheit wert ist, aber dies war die Designphilosophie für Java: Schreiben Sie Dinge explizit.
Ich weiß nicht, ob Java in Zukunft eine Typinferenz erhalten wird, aber IMO, das wäre eine große Revolution für die Sprache (wie Glenn Nelson erwähnte, wurde es als "un-java-like" beschrieben), und dann könnte man auch in Betracht ziehen, die zu löschen benenne Java zugunsten eines neuen Namens.
Wenn Sie eine JVM-Sprache mit Typinferenz verwenden möchten, können Sie Scala verwenden.
quelle
Ich kann mir ein paar mögliche Gründe vorstellen. Zum einen ist die explizite Eingabe selbstdokumentierend. Java macht dies im Allgemeinen zu einer Priorität vor der Konkretisierung. Ein weiterer Grund könnte in Fällen liegen, in denen der Typ etwas mehrdeutig ist. Zum Beispiel, wenn ein Typ oder ein Subtyp eine Routine erfüllen könnte. Angenommen, Sie möchten eine Liste verwenden, aber jemand kommt und verwendet eine Methode, die nur für ArrayList gilt. Die JIT würde eine ArrayList ableiten und weitermachen, selbst wenn Sie einen Kompilierungsfehler wollten.
quelle
Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error
- Ich verstehe das nicht. Die Typinferenz findet zum Zeitpunkt des Instatisierens einer Variablen statt, ohne dass eine Methode dafür aufgerufen wird. Könnten Sie vielleicht ein Beispiel dafür zeigen, was Sie gemeint haben?Dies widerspricht der gängigen Empfehlung, Variablen mit der allgemeinsten Schnittstelle zu deklarieren, die Ihren Anforderungen entspricht, und sie mit einer geeigneten Implementierungsklasse wie in zu initialisieren
Effektiv,
ist nichts anderes als syntaktischer Zucker für
Wenn Sie das wollen, kann Ihre IDE es
new ArrayList<String>()
mit "einem Klick" aus dem Ausdruck erzeugen (refactor / create local variable), aber denken Sie daran, dass es der Empfehlung "use interfaces" widerspricht.quelle