Collezione Immutable vs Unmodifiable

Dalla panoramica del framework delle collezioni :

Le raccolte che non supportano le operazioni di modifica (come add , remove e clear ) sono definite come non modificabili . Le collezioni che non sono modificabili sono modificabili .

Le raccolte che garantiscono inoltre che nessuna modifica nell’object Collection sia visibile sono definite immutabili . Le collezioni che non sono immutabili sono mutabili .

Non riesco a capire la distinzione.
Qual è la differenza tra immodificabile e immutabile qui?

Una collezione non modificabile è spesso un involucro attorno a una collezione modificabile a cui può ancora accedere l’altro codice . Quindi, mentre non puoi apportare alcuna modifica ad esso se hai solo un riferimento alla collezione non modificabile, non puoi fare affidamento sul fatto che il contenuto non cambi.

Una collezione immutabile garantisce che nulla può più cambiare la collezione. Se avvolge una raccolta modificabile, si assicura che nessun altro codice abbia accesso a quella raccolta modificabile. Si noti che sebbene nessun codice possa modificare gli oggetti a cui la raccolta contiene riferimenti, gli oggetti stessi possono essere comunque mutabili – la creazione di una collezione immutabile di StringBuilder non “blocca” in qualche modo tali oggetti.

Fondamentalmente, la differenza riguarda la possibilità che altro codice possa modificare la collezione dietro le tue spalle.

Fondamentalmente la collezione non modificabile è una vista, quindi indirettamente potrebbe ancora essere ‘modificata’ da qualche altro riferimento che è modificabile. Inoltre, proprio come una visione di sola lettura della collezione annother, quando la collezione di origine cambia la collezione non modificabile sarà sempre presente con gli ultimi valori.

La Collection comunque immutable può essere considerata una copia di una raccolta di sola lettura e non può essere modificata. In questo caso, quando la raccolta di origine cambia, la raccolta immutabile non riflette le modifiche

Ecco una prova per visualizzare questa differenza.

 @Test public void testList() { List modifiableList = new ArrayList(); modifiableList.add("a"); System.out.println("modifiableList:"+modifiableList); System.out.println("--"); //unModifiableList assertEquals(1, modifiableList.size()); List unModifiableList=Collections.unmodifiableList( modifiableList); modifiableList.add("b"); boolean exceptionThrown=false; try { unModifiableList.add("b"); fail("add supported for unModifiableList!!"); } catch (UnsupportedOperationException e) { exceptionThrown=true; System.out.println("unModifiableList.add() not supported"); } assertTrue(exceptionThrown); System.out.println("modifiableList:"+modifiableList); System.out.println("unModifiableList:"+unModifiableList); assertEquals(2, modifiableList.size()); assertEquals(2, unModifiableList.size()); System.out.println("--"); //immutableList List immutableList=Collections.unmodifiableList( new ArrayList(modifiableList)); modifiableList.add("c"); exceptionThrown=false; try { immutableList.add("c"); fail("add supported for immutableList!!"); } catch (UnsupportedOperationException e) { exceptionThrown=true; System.out.println("immutableList.add() not supported"); } assertTrue(exceptionThrown); System.out.println("modifiableList:"+modifiableList); System.out.println("unModifiableList:"+unModifiableList); System.out.println("immutableList:"+immutableList); System.out.println("--"); assertEquals(3, modifiableList.size()); assertEquals(3, unModifiableList.size()); assertEquals(2, immutableList.size()); } 

Produzione

 modifiableList:[a] -- unModifiableList.add() not supported modifiableList:[a, b] unModifiableList:[a, b] -- immutableList.add() not supported modifiableList:[a, b, c] unModifiableList:[a, b, c] immutableList:[a, b] -- 

Penso che la differenza principale sia che il proprietario di una collezione mutevole potrebbe voler fornire l’accesso alla raccolta ad un altro codice, ma fornire tale accesso attraverso un’interfaccia che non consente all’altra di modificare la raccolta (pur riservando tale capacità al codice proprietario). Pertanto la raccolta non è immutabile, ma a determinati utenti non è consentito modificare la raccolta.

Il tutorial di Oracle Collection Wrapper di Oracle ha questo da dire (enfasi aggiunta):

I wrapper non modificabili hanno due usi principali, come segue:

  • Per rendere una collezione immutabile una volta che è stata costruita. In questo caso, è buona norma non mantenere un riferimento alla collezione di accompagnamento. Questo garantisce assolutamente l’immutabilità.
  • Per consentire a determinati client l’accesso in sola lettura alle strutture dati. Si mantiene un riferimento alla raccolta di supporto ma si distribuisce un riferimento al wrapper. In questo modo, i client possono guardare ma non modificare, mantenendo l’accesso completo .

Se stiamo parlando di JDK Unmodifiable* vs guava Immutable* , in realtà la differenza è anche nelle prestazioni . Le raccolte immutabili possono essere più veloci e più efficienti in termini di memoria se non sono wrapper attorno alle collezioni regolari (le implementazioni JDK sono wrapper). Citando il team guava :

Il JDK fornisce metodi Collections.unmodifiableXXX, ma a nostro avviso, questi possono essere

< ...>

  • inefficiente: le strutture dati hanno ancora tutto il sovraccarico delle raccolte mutabili, inclusi i controlli delle modifiche simultanee, lo spazio extra nelle tabelle hash, ecc.

per citare i documenti java, a differenza dei wrapper di sincronizzazione, che aggiungono funzionalità alla raccolta incartata, i wrapper non modificabili eliminano le funzionalità. In particolare, toglie la possibilità di modificare la collezione intercettando tutte le operazioni che potrebbero modificare la raccolta e lanciare una UnsupportedOperationException .

I wrapper non modificabili hanno due usi principali, come segue:

Per rendere una collezione immutabile una volta che è stata costruita. In questo caso, è buona norma non mantenere un riferimento alla collezione di accompagnamento. Questo garantisce assolutamente l’immutabilità.

Per consentire a determinati client l’accesso in sola lettura alle strutture dati. Si mantiene un riferimento alla raccolta di supporto ma si distribuisce un riferimento al wrapper. In questo modo, i client possono guardare ma non modificare, mantenendo l’accesso completo.

Questo davvero riassume.

Come notato sopra, l’immodificabile non è immutabile perché una collezione non modificabile può essere alterata se, per esempio, una collezione non modificabile ha una collezione di delegati sottostante a cui fa riferimento un altro object e che l’object la modifica.

Per quanto riguarda l’immutabile, non è nemmeno ben definito. Tuttavia, generalmente significa che l’object “non cambierà”, ma che dovrebbe essere definito in modo ricorsivo. Ad esempio, posso definire immutabile su classi le cui variabili di istanza sono tutte primitive e i cui metodi non contengono argomenti e restituiscono primitive. I metodi quindi consentono in modo ricorsivo le variabili di istanza di essere immutabili e tutti i metodi per contenere argomenti che sono immutabili e che restituiscono valori immutabili. I metodi dovrebbero essere garantiti per restituire lo stesso valore nel tempo.

Supponendo che possiamo farlo, c’è anche il thread di concetto sicuro. E potresti essere indotto a pensare che immutabile (o non modificabile nel tempo) implichi anche la sicurezza del thread. Comunque non è questo il caso e questo è il punto principale che sto facendo qui che non è stato ancora notato in altre risposte. Posso build un object immutabile che restituisce sempre gli stessi risultati ma non è thread-safe. Per vedere questo suppongo di build una collezione immutabile mantenendo aggiunte e cancellazioni nel tempo. Ora la collezione immutabile restituisce i suoi elementi guardando la collezione interna (che può cambiare nel tempo) e quindi (internamente) aggiungendo ed eliminando gli elementi che sono stati aggiunti o cancellati dopo la creazione della collezione. Chiaramente, sebbene la collezione restituisca sempre gli stessi elementi, non è infallibile semplicemente perché non cambierà mai valore.

Ora possiamo definire immutabili come oggetti che sono thread safe e non cambieranno mai. Esistono linee guida per la creazione di classi immutabili che generalmente portano a tali classi, tuttavia, tieni presente che potrebbero esserci modi per creare classi immutabili, che richiedono attenzione alla sicurezza del thread, ad esempio, come descritto nell’esempio di raccolta “istantanea” sopra.