Iteratore fail-safe vs iteratore fail-fast

1. Introduzione

In questo articolo, introdurremo il concetto di iteratori fail-fast e fail-safe .

I sistemi Fail-Fast interrompono l'operazione il più velocemente possibile esponendo immediatamente i guasti e interrompendo l'intera operazione.

Al contrario, i sistemi fail-safe non interrompono un'operazione in caso di guasto. Tali sistemi cercano di evitare il più possibile di generare guasti.

2. Iteratori fail-fast

Gli iteratori veloci in Java non giocano quando la raccolta sottostante viene modificata.

Le raccolte mantengono un contatore interno chiamato modCount . Ogni volta che un elemento viene aggiunto o rimosso dalla raccolta , questo contatore viene incrementato.

Durante l'iterazione, ad ogni chiamata next () , il valore corrente di modCount viene confrontato con il valore iniziale. Se c'è una mancata corrispondenza, genera ConcurrentModificationException che interrompe l'intera operazione.

Gli iteratori predefiniti per le raccolte dal pacchetto java.util come ArrayList , HashMap , ecc. Sono Fail-Fast.

ArrayList numbers = // ... Iterator iterator = numbers.iterator(); while (iterator.hasNext()) { Integer number = iterator.next(); numbers.add(50); }

Nello snippet di codice precedente, ConcurrentModificationException viene generata all'inizio di un ciclo di iterazione successivo dopo l'esecuzione della modifica.

Non è garantito che il comportamento Fail-Fast si verifichi in tutti gli scenari poiché è impossibile prevedere il comportamento in caso di modifiche simultanee. Questi iteratori generano ConcurrentModificationException in base al massimo sforzo .

Se durante l'iterazione su una collezione , un elemento viene rimosso utilizzando Iterator s' remove () il metodo, che è del tutto sicuro e non un'eccezione .

Tuttavia, se il Collection 's remove () metodo viene utilizzato per la rimozione di un elemento, viene generata un'eccezione:

ArrayList numbers = // ... Iterator iterator = numbers.iterator(); while (iterator.hasNext()) { if (iterator.next() == 30) { iterator.remove(); // ok! } } iterator = numbers.iterator(); while (iterator.hasNext()) { if (iterator.next() == 40) { numbers.remove(2); // exception } }

3. Iteratori fail-safe

Gli iteratori fail-safe favoriscono la mancanza di errori rispetto all'inconveniente della gestione delle eccezioni.

Questi iteratori creano un clone dell'attuale Collection e lo ripetono. Se si verificano modifiche dopo la creazione dell'iteratore, la copia rimane intatta. Quindi, questi iteratori continuano a scorrere la raccolta anche se viene modificata.

Tuttavia, è importante ricordare che non esiste un iteratore veramente fail-safe. Il termine corretto è debolmente coerente.

Ciò significa che se una raccolta viene modificata durante l'iterazione, ciò che vede l' iteratore è debolmente garantito . Questo comportamento può essere diverso per le diverse raccolte ed è documentato in Javadoc di ciascuna di tali raccolte .

Tuttavia, gli iteratori fail-safe presentano alcuni svantaggi. Uno svantaggio è che non è garantito che l' iteratore restituisca dati aggiornati dalla raccolta , poiché funziona sul clone anziché sulla raccolta effettiva .

Un altro svantaggio è il sovraccarico di creare una copia della raccolta , sia per quanto riguarda il tempo che la memoria.

Gli iteratori sulle raccolte dal pacchetto java.util.concurrent come ConcurrentHashMap , CopyOnWriteArrayList , ecc. Sono di natura fail-safe.

ConcurrentHashMap map = new ConcurrentHashMap(); map.put("First", 10); map.put("Second", 20); map.put("Third", 30); map.put("Fourth", 40); Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); map.put("Fifth", 50); }

Nello snippet di codice sopra, stiamo usando l' iteratore fail-safe . Quindi, anche se un nuovo elemento viene aggiunto alla raccolta durante l'iterazione, non genera un'eccezione.

L'iteratore predefinitoper ConcurrentHashMap è debolmente coerente. Ciò significa che questo Iterator può tollerare modifiche simultanee, attraversa gli elementi così come esistevano quando Iterator è stato costruito e può (ma non è garantito) riflettere le modifiche alla Collection dopo la costruzione dell'Iterator .

Quindi, nello snippet di codice sopra, l'iterazione si ripete cinque volte, il che significa che rileva l'elemento appena aggiunto alla raccolta .

4. Conclusione

In questo tutorial, abbiamo visto cosa significano gli iteratori fail-safe e fail-fast e come questi vengono implementati in Java.

Il codice completo presentato in questo articolo è disponibile su GitHub.