2012-05-18 9 views
6

Utilizzando for(Type x:collection){...} quali tipi di raccolta ampiamente utilizzati rendono sicura la rimozione di x durante l'iterazione?Quali raccolte Java standard sono rimovibili durante l'iterazione?

E c'è un termine tecnico per questo a cui prestare attenzione in JavaDocs?

Chiarimento:

inizialmente ho solo chiesto di usare il for-each sintassi for(Type x:collection){...}. Comunque una risposta più completa descriverebbe questo stile E usando un normale loop basato su Iterator dove ci sono differenze ... la domanda è più su quali collezioni standard mi permettono di rimuovere gli elementi durante l'iterazione, E come eseguire l'iterazione per permettere questo.

+0

Intendi per ogni iterazione o iterazione di 'Iterator'? – Tharwen

+0

@Tharwen sono gli stessi ... – jjm

+1

@jjm: Ai fini di questa domanda, sono * molto * diversi. – NPE

risposta

5

Una tale raccolta è CopyOnWriteArrayList. Altre raccolte nel pacchetto java.util.concurrent condividono questa funzionalità.

Il fatto che i loro iteratori non generino mai uno ConcurrentModificationException è un effetto collaterale della semantica copy-on-write di questa classe: ogni volta che lo si modifica, l'array sottostante verrà copiato. Questo è fatto per consentire un accesso rapido e simultaneo a liste spesso lette ma raramente modificate.

Il JavaDoc spiega in questo modo (sottolineatura mia):

Il metodo "istantanea" stile iteratore utilizza un riferimento allo stato della matrice in corrispondenza del punto che l'iteratore è stato creato. Questo array non cambia mai durante la vita dell'iteratore, quindi l'interferenza è impossibile e l'iteratore è garantito per non gettare ConcurrentModificationException.

Oltre ai costi elevati di aggiornamenti questa implementazione ha alcuni ulteriori inconvenienti:

L'iteratore non rifletterà aggiunte, rimozioni o modifiche alla lista perché l'iteratore è stato creato. Le operazioni di modifica degli elementi sugli iteratori stessi (remove, set e add) non sono supportate. Questi metodi generano UnsupportedOperationException.

Nota che queste collezioni sono non vuole essere di utilità per consentire "facile" loop-e-rimozione, ma sono collezioni specializzate per l'uso in situazioni ad alto concorrenza dove molte discussioni hanno bisogno di accesso simultaneo ai dati che può ancora cambiare (ma di solito cambia raramente). Non sostituire semplicemente sostituendo ogni ArrayList con un CopyOnWriteArrayList.

+1

Anche alcune collezioni java.concurrent * sono. – kan

+0

Quindi stai dicendo che _none_ delle raccolte "vanilla" supportano questo? –

+0

CopyOnWriteArrayList iterator ** non ** supporta remove – bestsss

0

Come regola del pollice: Qualsiasi cosa w/Concurrent o Blocking nel suo nome, aka. ConcurrentLinkedList, ConcurrentSkipListSet, LinkedBlockingDeque, LinkedBlockingQueue, ecc. KeySet(), values ​​() di ConcurrentHashMap e ConcurrentSkipListMap e così via. La maggior parte di java.util.concurrent è ConcurrentModificationException e questo è buono.

COWArrayList è di solito utile per collezioni di piccole dimensioni o raramente modificate ... e si dovrebbe evitare il metodo esplicito set.

Una nota importante: l'utilizzo di iterator.remove dovrebbe essere sempre favorito per Collection.remove [quando availble, iteratore COWArrayList non supporta remove] (tranne CHM.entrySet(), che è l'impl in un modo buggy.). Tutte le strutture di accesso non casuale trarranno beneficio dal non dover cercare l'elemento che può essere O (n).

Complessivamente ConcurrentModificationException era un'idea semi-cotta e il suo impl. comporta alcuni effetti collaterali, incl. impedendo il funzionamento della memoria delle transazioni hardware. Impone costi di prestazioni extra che sono raramente necessari. HashMap ha un impl implacativo. w/un modCount volatile (che è scritto su modifica e letto su ogni itearyion, leggere è piuttosto gratuito su x86, però).

-1

Probabilmente una risposta in ritardo po ', ma Java 8 rende molto più facile da rimuovere gli elementi della collezione, mentre l'iterazione:

removeIf(Predicate<? super E> filter) 

Rimuove tutti gli elementi di questa collezione che soddisfa la data predicato.

Problemi correlati