In passato, ho detto di copiare in sicurezza una raccolta facendo qualcosa del tipo:
public static void doThing(List<String> strs) {
List<String> newStrs = new ArrayList<>(strs);
o
public static void doThing(NavigableSet<String> strs) {
NavigableSet<String> newStrs = new TreeSet<>(strs);
Ma questi costruttori "copia", metodi e flussi di creazione statici simili, sono davvero sicuri e dove sono specificate le regole? Con sicurezza intendo che le garanzie di integrità semantica di base offerte dal linguaggio Java e dalle raccolte vengono applicate contro un chiamante malintenzionato, supponendo che siano supportate da un ragionevole SecurityManagere che non vi siano difetti.
Sono felice con il metodo di lancio ConcurrentModificationException, NullPointerException, IllegalArgumentException, ClassCastException, ecc, o forse anche appeso.
Ho scelto Stringcome esempio di argomento di tipo immutabile. Per questa domanda, non mi interessano le copie profonde per raccolte di tipi mutabili che hanno i propri gotchas.
(Per essere chiari, ho esaminato il codice sorgente OpenJDK e ho una sorta di risposta per ArrayListe TreeSet.)
NavigableSete altre Comparableraccolte basate possono talvolta rilevare se una classe non si implementa compareTo()correttamente e generare un'eccezione. Non è chiaro cosa intendi con argomenti non attendibili. Vuoi dire che un malfattore crea una collezione di stringhe cattive e quando le copi nella tua collezione succede qualcosa di brutto? No, il framework delle collezioni è piuttosto solido, è in circolazione dall'1.2.
HashSet(e tutte le altre raccolte di hashing in generale) si basano sulla correttezza / integrità hashCodedell'implementazione degli elementi TreeSete PriorityQueuedipendono dal Comparator(e non puoi nemmeno crea una copia equivalente senza accettare il comparatore personalizzato se ce n'è uno), si EnumSetfida dell'integrità del enumtipo particolare che non viene mai verificata dopo la compilazione, quindi un file di classe, non generato con javaco creato a mano, può sovvertirlo.
new TreeSet<>(strs)dov'è strsa NavigableSet. Questa non è una copia in blocco, poiché il risultante TreeSetutilizzerà il comparatore della fonte, che è persino necessario per conservare la semantica. Se stai bene solo elaborando gli elementi contenuti, toArray()è la strada da percorrere; manterrà anche l'ordine di iterazione. Quando stai bene con "prendi elemento, convalida elemento, usa elemento", non hai nemmeno bisogno di fare una copia. I problemi iniziano quando si desidera verificare tutti gli elementi, seguiti dall'uso di tutti gli elementi. Quindi, non puoi fidarti di una TreeSetcopia con un comparatore personalizzato
checkcastper ciascun elemento è toArraycon un tipo specifico. Lo finiamo sempre. Le raccolte generiche non conoscono nemmeno il loro tipo di elemento effettivo, quindi i loro costruttori di copie non possono fornire una funzionalità simile. Certo, puoi rinviare qualsiasi controllo al giusto uso precedente, ma poi non so a cosa mirino le tue domande. Non hai bisogno di "integrità semantica", quando stai bene controllando e fallendo immediatamente prima di usare gli elementi.