Puede hacer lo que desee si utiliza un objeto iterador para revisar los elementos de su conjunto. Puedes eliminarlos sobre la marcha y está bien. Sin embargo la eliminación de ellos, mientras que en un bucle ("estándar", de la de cada especie) que se meterán en problemas:
Set<Integer> set = new TreeSet<Integer>();
set.add(1);
set.add(2);
set.add(3);
//good way:
Iterator<Integer> iterator = set.iterator();
while(iterator.hasNext()) {
Integer setElement = iterator.next();
if(setElement==2) {
iterator.remove();
}
}
//bad way:
for(Integer setElement:set) {
if(setElement==2) {
//might work or might throw exception, Java calls it indefined behaviour:
set.remove(setElement);
}
}
Según comentario de @ mrgloom, Aquí hay más detalles de por qué el "malo" La forma descrita arriba es, bueno ... mala:
Sin entrar en demasiados detalles sobre cómo Java implementa esto, en un nivel alto, podemos decir que la "mala" manera es mala porque está claramente estipulada como tal en la documentación de Java:
https://docs.oracle.com/javase/8/docs/api/java/util/ConcurrentModificationException.html
estipulan, entre otras cosas, de que (el énfasis es mío):
"Por ejemplo, generalmente no es permisible para un hilo de modificar una colección mientras que otro hilo está interactuando sobre ella. En en general, los resultados de la iteración no están definidos en estas circunstancias . Algunas implementaciones Iterator (incluyendo los de todos las implementaciones de recogida de propósito general que proporciona el JRE) pueden optar por lanzar esta excepción si se detecta este comportamiento "(...)
" Tenga en cuenta que esta excepción no siempre indican que un objeto ha sido modificado simultáneamente por un hilo diferente. Si un único hilo emite una secuencia de invocaciones de método que infringe el contrato de un objeto, el objeto puede lanzar esta excepción. Para ejemplo, si un hilo modifica una colección directamente si bien es iterar sobre la colección con un iterador fail-fast, el iterador arrojará esta excepción "
Para ir más en detalles:. Un objeto que se puede usar en un ciclo forEach necesita implementar la interfaz "java.lang.Iterable" (javadoc here). Esto produce un Iterator (a través del método "Iterator" que se encuentra en esta interfaz), que se instancia a petición y lo hará contienen internamente una referencia al objeto Iterable desde el que se creó. Sin embargo, cuando se utiliza un objeto Iterable en un ciclo forEach, la instancia de este iterador está oculta para el usuario (no puede acceder a ella usted mismo). de cualquier manera).
Esto, junto con el hecho de que un iterador es bastante estable, es decir, para hacer su magia y tener respuestas coherentes para sus métodos "siguiente" y "tiene ahora", necesita que el objeto de respaldo no cambie por otra cosa que el iterador mismo mientras está iterando, lo hace de modo que arroje una excepción tan pronto como detecte que algo cambió en el objeto de respaldo mientras se itera sobre él.
Java llama a esta iteración "a prueba de fallos": es decir, hay algunas acciones, normalmente aquellas que modifican una instancia Iterable (mientras un iterador está iterando sobre ella). La parte de "falla" de la noción de "falla rápida" se refiere a la capacidad de un iterador para detectar cuándo ocurren tales acciones de "falla". La parte "rápida" del "fail-fast" (y, que en mi opinión debería llamarse "best-effort-fast"), terminará la iteración mediante ConcurrentModificationException tan pronto como como puede detectar que un " fallar "la acción ha sucedido.
debe seleccionar una respuesta adecuada – MarianP