Mesmo programando há algum tempo em Java, há excepções que nos surpreendem e nos mostram que até somos capazes de não perceber nada disto.
Um colega obtinha, por vezes, uma excepção ConcurrentModificationException ao percorrer uma lista com um iterador. O código era uma versão mais complexa do seguinte excerto:
List lista = new ArrayList(); lista.add("obj1"); lista.add("obj2"); for(Iterator it=lista.iterator();it.hasNext();) { String elem = (String) it.next(); if("obj1".equals(elem)) { lista.add("elem3"); } }
O que acontecia era, se uma condição se verificasse, era removido um elemento da lista. Quando tal acontecia, a próxima vez que o método next() do iterador fosse executado, obtínhamos a excepção. Ao olhar para o nome da excepção
, a primeira ideia foi que, dado a lista não ser sincronizada, estavam threads concorrentes a aceder ao objecto. No entanto, a conclusão foi mais simples e lógica.
Quando se
altera a estrutura de uma lista – adicionando ou removendo elementos – à qual está ligado um iterador que estamos a percorrer, esse iterador fica inválido. Limita-se a verificar se fizemos operações que alterassem a lista, se sim, lança uma ConcurrentModificationException. Não que seja um nome de excepção adequado.
A este comportamento dá-se o nome de fail-fast, pois o iterador lança a excepção mal detecta que existiu uma alteração à lista e não fica à espera que ocorra um erro, não determinístico, mais tarde, ao percorrer o iterador.
De notar que o mesmo ocorre se usarmos o foreach do java 5 e removermos elementos.