Verwendung von Java 9 Collection Factories

8

Im Zusammenhang mit den Kommentaren und Antworten in List.of () oder Collections.emptyList () und List.of (...) oder Collections.unmodiableList () Ich habe zwei folgende Faustregeln (die auch für Set gelten) und Map factories entsprechend).

  1. Ersetzen Sie nicht alle Vorkommen

Verwenden Sie weiterhin Collections.emptyList() für die Lesbarkeit und wenn z. lazy field members wie:

initialisieren %Vor%
  1. Verwenden Sie neue Factories als Builder für Methodenargumente

Verwenden Sie neue Fabriken List.of() und Varianten als schnelle und weniger typisierte Version, wenn Sie eine ausführbare Datei mit List -Parametern aufrufen. Hier sind meine aktuellen Substitutionsmuster:

%Vor%

In einer fiktiven Verwendung von Collections.indexOfSubList sind die folgenden Zeilen

%Vor%

liest

%Vor%

Stimmen Sie (nicht) zu?

    
Sormuras 30.11.2016, 12:46
quelle

2 Antworten

9

Im Allgemeinen ist die Verwendung der neuen Fabriken für neuen Code sicher, wo kein Code vorhanden ist, der vom Verhalten der vorhandenen Sammlungen abhängt.

Es gibt mehrere Gründe dafür, dass die neuen Auflistungsfactories keine Drop-In-Ersetzungen für Code sind, der Sammlungen mithilfe der vorhandenen APIs initialisiert. Offensichtlich ist Unveränderlichkeit einer der prominentesten Gründe; Wenn Sie die Sammlung später ändern müssen, kann sie offensichtlich nicht unveränderlich sein! Aber es gibt auch andere Gründe, einige davon ziemlich subtil.

Ein Beispiel für den Austausch vorhandener APIs mit den neuen APIs finden Sie unter JDK-8134373 . Die Review-Themen sind hier: Part1 Teil 2 .

Hier ist eine Zusammenfassung der Probleme.

Array Wrapping vs Copying Manchmal haben Sie ein Array, z. ein Varargs-Parameter, und Sie möchten es als eine Liste verarbeiten. Manchmal ist Arrays.asList die geeignetste Sache hier, da es nur ein Wrapper ist. Im Gegensatz dazu erstellt List.of eine Kopie, die möglicherweise verschwenderisch ist. Auf der anderen Seite hat der Aufrufer immer noch ein Handle für das umgebrochene Array und kann es modifizieren, was ein Problem sein könnte. Manchmal möchten Sie also die Kosten für das Kopieren übernehmen, wenn Sie beispielsweise einen Verweis auf den Liste in einer Instanzvariable.

Hash-Collection-Iterationsreihenfolge. Die neuen Strukturen Set.of und Map.of geben ihre Iterationsreihenfolge zufällig an. Die Iterationsreihenfolge von HashSet und HashMap ist nicht definiert, aber in der Praxis erweist es sich als relativ stabil. Code kann unbeabsichtigte Abhängigkeiten von der Iterationsreihenfolge entwickeln. Das Wechseln zu den neuen Auflistungsfactorys kann alten Code den Abhängigkeiten der Iterationsreihenfolge aussetzen und latente Fehler auftauchen.

Verbot von Nullen. Die neuen Sammlungen verbieten Nullen vollständig, während die gemeinsamen nicht-gleichzeitigen Sammlungen ( ArrayList , HashMap ) sie zulassen.

Serialisierungsformat. Die neuen Sammlungen haben ein anderes Serialisierungsformat als die alten. Wenn die Auflistung serialisiert ist oder in einer anderen Klasse gespeichert ist, die serialisiert ist, unterscheidet sich die serialisierte Ausgabe. Dies könnte oder könnte kein Problem sein. Wenn Sie jedoch mit anderen Systemen zusammenarbeiten möchten, könnte dies ein Problem darstellen. Insbesondere wenn Sie die serialisierte Form der neuen Auflistungen an eine Java 8-JVM übertragen, wird die Deserialisierung fehlschlagen, da die neuen Klassen in Java 8 nicht vorhanden sind.

Striktes Verhalten der Mutator-Methode. Die neuen Sammlungen sind unveränderlich, also werfen sie natürlich UnsupportedOperationException , wenn Mutator-Methoden aufgerufen werden. Es gibt jedoch einige Randfälle, bei denen das Verhalten nicht in allen Sammlungen konsistent ist. Zum Beispiel

%Vor%

tut nichts, während

%Vor%

wird UOE werfen. Im Allgemeinen sind die neuen Sammlungen und die unmodifizierbaren Wrapper konsistent streng, wenn UOE bei irgendeinem Aufruf einer Mutator-Methode geworfen wird, selbst wenn keine tatsächliche Mutation auftreten würde. Andere unveränderbare Sammlungen wie die von Collections.empty* und Collections.singleton* werfen UOE nur dann, wenn eine tatsächliche Mutation auftreten würde.

Duplikate. Die neuen Fabriken Set und Map lehnen doppelte Elemente und Schlüssel ab. Dies ist normalerweise kein Problem, wenn Sie eine Auflistung mit einer Liste von Konstanten initialisieren. In der Tat, wenn eine Liste von Konstanten ein Duplikat hat, ist es wahrscheinlich ein Fehler. Wo dies möglicherweise ein Problem ist, wenn ein Aufrufer eine Sammlung oder ein Array (z. B. Varags) von Elementen übergeben darf. Wenn der Aufrufer Duplikate übergibt, würden die vorhandenen APIs die Duplikate ignorieren, während die neuen Factories IllegalArgumentException ausgeben. Dies ist eine Verhaltensänderung, die sich auf Anrufer auswirken kann.

Keines dieser Probleme ist ein fatales Problem, aber Verhaltensunterschiede, auf die Sie beim Nachrüsten von vorhandenem Code achten sollten. Leider bedeutet dies, dass ein Massenersatz bestehender Anrufe mit den neuen Sammelfabriken wahrscheinlich nicht ratsam ist. Es ist wahrscheinlich notwendig, an jedem Standort eine Inspektion durchzuführen, um mögliche Auswirkungen der Verhaltensänderungen zu bewerten.

    
Stuart Marks 03.12.2016, 02:57
quelle
7

(Im) Mutabilität

Zuallererst ist es wichtig zu beachten, dass die Sammelfabriken unveränderliche Varianten zurückgeben. Leider wird dies im Typsystem nicht angezeigt, so dass Sie das manuell / mental verfolgen müssen. Dies verbietet bereits einige Ersetzungen, die sich sonst möglicherweise lohnen würden, daher muss es 0 werden. in Ihrer Liste von Regeln. :)

Beispielsweise könnte das Erstellen einer Auflistung von Startelementen, die später von anderem Code geändert werden, wie folgt aussehen:

%Vor%

Wäre toll, einfach commonLetters = Set.of("a", "e"); zu schreiben, aber das wird wahrscheinlich anderen Code zerstören, da die zurückgegebene Menge unveränderlich ist.

Konstanten

Die (Un) Veränderlichkeitsdiskussion führt unmittelbar zu Konstanten. Dies war ein wichtiger Grund, sie vorzustellen! Vorbei sind die Tage, an denen Sie einen statischen Initialisierungsblock benötigen, um diese COMMON_LETTERS -Konstante zu erstellen. Dies wäre also der Ort, an dem ich zuerst nach Anwendungsfällen suchen würde.

Ersetzen

Wie Sie schon gesagt haben, scheint es keinen Grund zu geben, die Aufrufe von Collections::empty... , Collections::singleton... oder Arrays::asList nur zum Spaß zu ersetzen. Was ich jedoch tun würde, sobald ich anfange, die neuen Methoden in einer Klasse zu verwenden, würde ich die alten Varianten ebenso ersetzen, um den Code auf weniger Konzepte zu verlassen, die das Verständnis erleichtern.

Präferenz

Das letzte Argument ist auch eines, das im Allgemeinen für die of() -Varianten gelten könnte. Während Collections::empty... und Collections::singleton... etwas deutlicher in Bezug auf ihre Absicht sind, tendiere ich dazu, zu sagen, dass of , egal wie viele Argumente Sie haben, diesen Vorteil ausgleicht, indem Sie Code schreiben, der als Ganzes weniger Konzepte verwendet .

Ich sehe keinen Grund, Arrays::asList weiter zu verwenden.

    
Nicolai 30.11.2016 13:15
quelle

Tags und Links