In der Vergangenheit habe ich gesagt, eine Sammlung sicher zu kopieren, um Folgendes zu tun:
public static void doThing(List<String> strs) {
List<String> newStrs = new ArrayList<>(strs);
oder
public static void doThing(NavigableSet<String> strs) {
NavigableSet<String> newStrs = new TreeSet<>(strs);
Aber sind diese "Kopier" -Konstruktoren, ähnliche statische Erstellungsmethoden und Streams, wirklich sicher und wo sind die Regeln angegeben? Mit sicher meine ich die grundlegenden semantischen Integritätsgarantien , die von der Java-Sprache und den Sammlungen angeboten werden, die gegen einen böswilligen Anrufer erzwungen werden, vorausgesetzt, sie werden von einem vernünftigen unterstützt SecurityManagerund es gibt keine Fehler.
Ich bin glücklich mit dem Verfahren werfen ConcurrentModificationException, NullPointerException, IllegalArgumentException, ClassCastException, usw., oder vielleicht sogar hängen.
Ich habe Stringals Beispiel für ein unveränderliches Typargument gewählt. Für diese Frage interessieren mich keine tiefen Kopien für Sammlungen veränderlicher Typen, die ihre eigenen Fallstricke haben.
(Um klar zu sein, habe ich mir den OpenJDK-Quellcode angesehen und habe eine Antwort auf ArrayListund TreeSet.)
NavigableSetund andere Comparablebasierte Sammlungen können manchmal erkennen, ob eine Klasse nicht compareTo()korrekt implementiert ist , und eine Ausnahme auslösen. Es ist ein bisschen unklar, was Sie unter nicht vertrauenswürdigen Argumenten verstehen. Du meinst, ein Übeltäter bastelt eine Sammlung von schlechten Saiten und wenn du sie in deine Sammlung kopierst, passiert etwas Schlimmes? Nein, das Sammlungs-Framework ist ziemlich solide, es gibt es seit 1.2.
HashSet(und alle anderen Hashing-Sammlungen im Allgemeinen). Dies hängt von der Richtigkeit / Integrität der hashCodeImplementierung der Elemente ab TreeSetund PriorityQueuehängt von der ab Comparator(und Sie können nicht einmal Erstellen Sie eine äquivalente Kopie, ohne den benutzerdefinierten Komparator zu akzeptieren (falls vorhanden), und EnumSetvertrauen Sie auf die Integrität des bestimmten enumTyps, der nach der Kompilierung nie überprüft wird, sodass eine Klassendatei, die nicht mit javacoder in Handarbeit erstellt wurde, diese untergraben kann.
new TreeSet<>(strs)wo strsist ein NavigableSet. Dies ist keine Massenkopie, da das Ergebnis TreeSetden Komparator der Quelle verwendet, der sogar erforderlich ist, um die Semantik beizubehalten. Wenn Sie nur die enthaltenen Elemente verarbeiten können, toArray()ist dies der richtige Weg. Es wird sogar die Iterationsreihenfolge beibehalten. Wenn Sie mit "Element nehmen, Element validieren, Element verwenden" einverstanden sind, müssen Sie nicht einmal eine Kopie erstellen. Die Probleme beginnen, wenn Sie alle Elemente überprüfen und anschließend alle Elemente verwenden möchten. Dann können Sie einer TreeSetKopie mit benutzerdefiniertem Komparator nicht vertrauen
checkcastfür jedes Element erfolgt toArraymit einem bestimmten Typ. Wir enden immer damit. Die generischen Sammlungen kennen nicht einmal ihren tatsächlichen Elementtyp, sodass ihre Kopierkonstruktoren keine ähnliche Funktionalität bereitstellen können. Natürlich können Sie jede Überprüfung auf die richtige vorherige Verwendung verschieben, aber dann weiß ich nicht, worauf Ihre Fragen abzielen. Sie benötigen keine "semantische Integrität", wenn Sie unmittelbar vor der Verwendung von Elementen prüfen und fehlschlagen können.