Digamos que tengo un conjunto de enteros y quiero incrementar cada entero en el conjunto. ¿Cómo haría esto?
¿Puedo agregar y eliminar elementos del conjunto mientras lo itero?
¿Necesitaría crear un nuevo conjunto en el que "copiaría y modificaría" los elementos mientras iteraba el conjunto original?
EDITAR: ¿Qué pasa si los elementos del conjunto son inmutables?
cannot
lugar decan
? ¿Como en, enYou cannot safely remove
lugar deYou can safely remove
? Parece una contradicción en ese primer párrafo.error: incompatible types: Object cannot be converted to Integer
Puede hacer lo que quiera si usa un objeto iterador para repasar los elementos de su conjunto. Puede eliminarlos sobre la marcha y está bien. Sin embargo, eliminarlos mientras está en un bucle for (ya sea "estándar", de cada tipo) le traerá 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 el comentario de @ mrgloom, aquí hay más detalles sobre por qué la forma "mala" descrita anteriormente es, bueno ... mala:
Sin entrar en demasiados detalles sobre cómo Java implementa esto, a un alto nivel, podemos decir que la forma "mala" es mala porque está claramente estipulado como tal en los documentos de Java:
https://docs.oracle.com/javase/8/docs/api/java/util/ConcurrentModificationException.html
estipular, entre otros, que (énfasis mío):
Para entrar más en detalles: un objeto que se puede usar en un bucle forEach necesita implementar la interfaz "java.lang.Iterable" (javadoc aquí ). Esto produce un iterador (a través del método "Iterador" que se encuentra en esta interfaz), que se crea una instancia bajo demanda, y contendrá internamente una referencia al objeto Iterable desde el cual fue creado. Sin embargo, cuando se usa un objeto Iterable en un bucle forEach, la instancia de este iterador está oculta para el usuario (no puede acceder a él de ninguna manera).
Esto, junto con el hecho de que un iterador tiene bastante estado, es decir, para hacer su magia y tener respuestas coherentes para sus métodos "next" y "hasNext", necesita que el objeto de respaldo no sea cambiado por otra cosa que no sea el iterador. mientras está iterando, lo hace para que arroje una excepción tan pronto como detecte que algo cambió en el objeto de respaldo mientras está iterando sobre él.
Java llama a esta iteración "a prueba de fallas": es decir, hay algunas acciones, generalmente 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" de la "falla rápida" (y, que en mi opinión debería llamarse "mejor esfuerzo rápido"), terminará la iteración a través de ConcurrentModificationException tan pronto como pueda detectar que una acción "falla" ocurrir.
fuente
No me gusta mucho la semántica del iterador, por favor considere esto como una opción. También es más seguro ya que publica menos de su estado interno
private Map<String, String> JSONtoMAP(String jsonString) { JSONObject json = new JSONObject(jsonString); Map<String, String> outMap = new HashMap<String, String>(); for (String curKey : (Set<String>) json.keySet()) { outMap.put(curKey, json.getString(curKey)); } return outMap; }
fuente
Puede crear una envoltura mutable del primitivo int y crear un conjunto de esos:
class MutableInteger { private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } } class Test { public static void main(String[] args) { Set<MutableInteger> mySet = new HashSet<MutableInteger>(); // populate the set // .... for (MutableInteger integer: mySet) { integer.setValue(integer.getValue() + 1); } } }
Por supuesto, si está utilizando un HashSet, debe implementar el método hash, equals en su MutableInteger, pero eso está fuera del alcance de esta respuesta.
fuente
En primer lugar, creo que intentar hacer varias cosas a la vez es una mala práctica en general y te sugiero que pienses en lo que estás intentando conseguir.
Sin embargo, sirve como una buena pregunta teórica y, por lo que deduzco, la
CopyOnWriteArraySet
implementación de lajava.util.Set
interfaz satisface sus requisitos especiales.http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/CopyOnWriteArraySet.html
fuente