JDK 7: Der Diamantoperator

Project Coin bietet zahlreiche "kleine Sprachverbesserungen" als Teilmenge der neuen JDK 7-Funktionen. Ich habe kürzlich über das Einschalten von Strings durch Project Coin gebloggt und in diesem Beitrag schreibe ich über den neuen Diamond Operator ( ).

Der Diamond Operator reduziert einige der Ausführlichkeiten von Java in Bezug auf Generika, indem der Compiler Parametertypen für Konstruktoren generischer Klassen ableitet. Der ursprüngliche Vorschlag zum Hinzufügen des Diamond Operator zur Java-Sprache wurde im Februar 2009 gemacht und enthält dieses einfache Beispiel:

Betrachten Sie beispielsweise die folgende Zuweisungsanweisung:

Karte Anagramme = neue HashMap ();

Dies ist ziemlich langwierig, daher kann es durch Folgendes ersetzt werden:

Karte Anagramme = neue HashMap ();

Das obige Beispiel in Jeremy Mansons Vorschlag (der eines der ersten als Antwort auf eine Aufforderung zur Einreichung von Ideen für Projektmünzen war) ist einfach, zeigt jedoch angemessen, wie der Diamantoperator in JDK 7 angewendet wird. Mansons Vorschlag liefert auch wichtige Informationen dazu, warum dieser Zusatz war wünschenswert:

Die Anforderung, dass Typparameter unnötig dupliziert werden müssen, gefällt

das ermutigt einen unglücklichen

Überfülle an statischen Factory-Methoden, einfach weil Typinferenz

arbeitet mit Methodenaufrufen.

Mit anderen Worten, die JDK 7-Projektmünze, die einen Diamantoperator hinzufügt, bringt Konstruktoren, die mit Methoden verfügbar waren, Typinferenz. Bei Methoden erfolgt die Typinferenz implizit, wenn die explizite Parametertypspezifikation weggelassen wird. Bei der Instanziierung muss andererseits der Diamantoperator explizit angegeben werden, um den Compiler anzuweisen, auf den Typ zu schließen.

In seinem ursprünglichen Vorschlag weist Manson darauf hin, dass die Syntax ohne einen speziellen Diamantoperator nicht verwendet werden kann, um implizit Typen für Instanziierungen abzuleiten, da "aus Gründen der Abwärtskompatibilität new Map () einen Rohtyp angibt und daher nicht für Typen verwendet werden kann Inferenz." Die Seite "Typinferenz" der generischen Lektion zum Erlernen der Java-Sprache in den Java-Lernprogrammen enthält einen Abschnitt mit dem Titel "Typinferenz und Instanziierung generischer Klassen", der bereits aktualisiert wurde, um Java SE 7 widerzuspiegeln. In diesem Abschnitt wird auch beschrieben, warum das Special Der Operator muss angegeben werden, um den Compiler explizit über die Verwendung der Typinferenz bei der Instanziierung zu informieren:

Beachten Sie, dass Sie den Diamantoperator angeben müssen, um die automatische Typinferenz während der generischen Klasseninstanziierung nutzen zu können. Im folgenden Beispiel generiert der Compiler eine ungeprüfte Konvertierungswarnung, da der HashMap () -Konstruktor auf den HashMap-Rohtyp und nicht auf die Map verweist Art

In Punkt 24 ("Ungeprüfte Warnungen beseitigen") der zweiten Ausgabe von Effective Java betont Josh Bloch in Fettdruck : "Beseitigen Sie jede ungeprüfte Warnung, die Sie können." Bloch zeigt ein Beispiel für die ungeprüfte Konvertierungswarnung, die auftritt, wenn Code kompiliert wird, der einen Rohtyp auf der rechten Seite einer Deklaration verwendet. Die nächste Codeliste zeigt Code, der zu dieser Warnung führt.

final Map
     
       statesToCities = new HashMap(); // raw! 
     

Die nächsten beiden Screenshots zeigen die Antwort des Compilers auf die obige Codezeile. Das erste Bild zeigt die Meldung, wenn keine -Xlint-Warnungen aktiviert sind, und das zweite zeigt die explizitere Warnung, die auftritt, wenn -Xlint:uncheckedsie als Argument für javac bereitgestellt wird.

Bei effektivem Java weist Bloch darauf hin, dass diese bestimmte ungeprüfte Warnung leicht zu beheben ist, indem der Parametertyp explizit für die Instanziierung der generischen Klasse angegeben wird. Mit JDK 7 wird dies noch einfacher! Anstatt den expliziten Text mit diesen Typnamen hinzufügen zu müssen, können die Typen in vielen Fällen abgeleitet werden, und die Angabe des Diamantoperators weist den Compiler an, diese Schlussfolgerung zu ziehen, anstatt den Rohtyp zu verwenden.

Die nächste Java-Codeliste enthält vereinfachte Beispiele für diese Konzepte. Es gibt Methoden, die die Instanziierung eines Rohsatzes, die Instanziierung eines Satzes mit expliziter Angabe seines Parametertyps und die Instanziierung eines Satzes mit Parametertyp demonstrieren, der aufgrund der Angabe des Diamantoperators ( ) abgeleitet wurde.

package dustin.examples; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import static java.lang.System.out; /** * Very simple demonstration of JDK 7's/Project Coin's "Diamond Operator." */ public class DiamondOperatorDemo { /** Use of "raw" type. */ private static Set rawWithoutExplicitTyping() { final Set names = new HashSet(); addNames(names); return names; } /** Explicitly specifying generic class's instantiation parameter type. */ private static Set explicitTypingExplicitlySpecified() { final Set names = new HashSet(); addNames(names); return names; } /** * Inferring generic class's instantiation parameter type with JDK 7's * 'Diamond Operator.' */ private static Set explicitTypingInferredWithDiamond() { final Set names = new HashSet(); addNames(names); return names; } private static void addNames(final Set namesToAddTo) { namesToAddTo.add("Dustin"); namesToAddTo.add("Rett"); namesToAddTo.add("Homer"); } /** * Main executable function. */ public static void main(final String[] arguments) { out.println(rawWithoutExplicitTyping()); out.println(explicitTypingExplicitlySpecified()); out.println(explicitTypingInferredWithDiamond()); } } 

Wenn der obige Code kompiliert wird, führt nur der "rohe" Fall zu einer Warnung.

An dieser Stelle kann es aufschlussreich sein, zu sehen, was Javap über diese drei Methoden sagt. Dies geschieht in diesem Fall mit dem Befehl (die -vOption für verbose gibt alle wichtigen Details an und -pzeigt diese wichtigen Details für die privateMethoden an):

javap -v -p -classpath classes dustin.examples.DiamondOperatorDemo 

Da diese Methoden alle in einer einzigen Klasse waren, gibt es einen einzigen Ausgabestream für die gesamte Klasse. Um den Vergleich zu vereinfachen, habe ich die Ausgabe jedoch ausgeschnitten und in ein Format eingefügt, das die Javap-Ausgabe für jede Methode gegeneinander ausrichtet. Jede Spalte repräsentiert die javapAusgabe für eine der Methoden. Ich habe die Schriftfarbe der jeweiligen Methode in Blau geändert, um sie hervorzuheben und die Ausgabe dieser Spalte zu kennzeichnen.

Abgesehen von den Namen der Methoden selbst gibt es keinen Unterschied in der javapAusgabe. Dies liegt daran, dass das Löschen von Java-Generika-Typen bedeutet, dass die Differenzierung nach Typ zur Laufzeit nicht verfügbar ist. Das Java-Lernprogramm zu Generika enthält eine Seite mit dem Namen Type Erasure, auf der Folgendes erläutert wird:

Der Compiler entfernt alle Informationen zum tatsächlichen Typargument zur Kompilierungszeit.

Typlöschung ist vorhanden, damit neuer Code weiterhin mit Legacy-Code verbunden werden kann. Die Verwendung eines Rohtyps aus einem anderen Grund wird als schlechte Programmierpraxis angesehen und sollte nach Möglichkeit vermieden werden.

Wie das obige Zitat uns erinnert, bedeutet Löschen, dass sich der Bytecode eines Rohtyps nicht von einem explizit typisierten Parametertyp unterscheidet, sondern Entwickler dazu ermutigt, keine Rohtypen zu verwenden, außer für die Integration in Legacy-Code.

Fazit

Die Aufnahme des Diamantoperators ( ) in Java SE 7 bedeutet, dass Code, der generische Klassen instanziiert, weniger ausführlich sein kann. Codierungssprachen im Allgemeinen und Java im Besonderen tendieren zu Ideen wie Konvention über Konfiguration, Konfiguration durch Ausnahmen und so oft wie möglich zu Schlussfolgerungen, anstatt explizite Spezifikationen zu erfordern. Dynamisch typisierte Sprachen sind für ihre Typinferenz bekannt, aber selbst statisch typisiertes Java kann mehr davon als es tut, und der Diamantoperator ist ein Beispiel dafür.

Originalbeitrag verfügbar unter //marxsoftware.blogspot.com/

Diese Geschichte "JDK 7: The Diamond Operator" wurde ursprünglich von JavaWorld veröffentlicht.