L'unmodifiableList è sostenuta da Lista originale
Che unmodifiableList
metodo nella Collections
classe di utilità non crea una nuova lista, si crea una pseudo-list sostenuta dalla lista originale. Qualsiasi tentativo di aggiunta o rimozione effettuato tramite l'oggetto "non modificabile" verrà bloccato, quindi il nome è all'altezza del suo scopo. Ma in effetti, come hai mostrato, la lista originale può essere modificata e contemporaneamente influenza la nostra lista secondaria non-non-modificabile.
Questo è scritto nella documentazione della classe:
Restituisce una vista immodificabile della lista specificata. Questo metodo consente ai moduli di fornire agli utenti accesso "di sola lettura" agli elenchi interni. Le operazioni di query sull'elenco restituito "read through" all'elenco specificato e i tentativi di modifica dell'elenco restituito, diretti o tramite il relativo iteratore, determinano un'eccezione UnsupportedOperationException.
Quella quarta parola è la chiave: view
. Il nuovo oggetto elenco non è una nuova lista. È una sovrapposizione. Proprio come tracing paper o transparency film su un disegno si impedisce di fare segni sul disegno, non ti impedisce di andare sotto per modificare il disegno originale.
Morale della storia: non utilizzare Collections.unmodifiableList per creare copie difensive di elenchi.
Idem per Collections.unmodifiableMap
, Collections.unmodifiableSet
e così via.
Google Guava
Invece del Collections
di classe, per la programmazione difensiva mi consiglia di utilizzare la libreria Google Guava e la sua struttura ImmutableCollections.
È possibile creare una nuova lista.
public static final ImmutableList<String> ANIMALS = ImmutableList.of(
dog,
cat,
bird);
Oppure è possibile effettuare una copia difensiva di un elenco esistente. In questo caso otterrai una nuova lista separata. L'eliminazione dall'elenco originale sarà non influenzerà (restringerà) l'elenco immutabile.
ImmutableList<String> ANIMALS = ImmutableList.copyOf(originalList); // defensive copy!
Ma ricordate, mentre propria definizione della collezione è separata, gli oggetti contenuti sono condivisi sia dalla lista originale e nuova lista immutabile. Nel fare quella copia difensiva, non stiamo duplicando l'oggetto "cane". Solo un oggetto cane rimane in memoria, entrambi gli elenchi contengono un riferimento che punta allo stesso cane. Se le proprietà nell'oggetto "cane" vengono modificate, entrambe le raccolte puntano allo stesso oggetto cane singolo e quindi entrambe le raccolte vedranno il valore della proprietà fresca del cane.
Mentre StackOverflow ha domande simili su Collections.unmodifiable ..., non sono riuscito a trovare nessuna risposta a questo problema in modo semplice e diretto. Così ho postato questa domanda e risposta. –
Javadoc di 'Collections.unmodifiableList' è molto chiaro che solo la lista restituita non è modificabile. Ti aspettavi davvero che questa chiamata rendesse l'elenco originale non modificabile? – wero
@wero "Il Javadoc ... è molto chiaro ..." - Mi permetto di dissentire. Il testo del doc, "Restituisce una vista non modificabile dell'elenco specificato." È tutt'altro che chiaro sulla raccolta originale che supporta il nuovo oggetto. Soprattutto non chiaro ai non addetti in quanto Java non ha una "visione" definita. Una rapida ricerca su Google rivelerà che non sono il solo a fare questa lettura errata. –