PDA

View Full Version : [Java] Rimozione iterativa da una lista


Lim
09-07-2010, 11:56
Salve a tutti.
Sono appena incappato in un problema nella gestione delle liste.

Ho un insieme di oggetti che popolano una lista.
Ad intervalli di tempo prestabiliti, vorrei controllare OGNI elemento della lista per verificare una condizione su un attributo di ogni oggetto. Se la condizione è vera (o falsa) l'oggetto in questione deve essere rimosso dalla lista.
Ho tentato due approcci, per semplicità incollo il codice qui sotto:


public List<MyObj> lista=new ArrayList<MyObj>();
...
...
int size=lista.size();
for(int i=0;i<size;i++){
if(!(lista.get(i).isAlive())) {
lista.remove(i);
}
}


Questa prima implementazione restituisce (giustamente):
java.lang.IndexOutOfBoundsException, esattamente alla metà delle dimensioni iniziali della lista.

L'altra implementazione, invece:

for(MyObj o: lista){
if(!(o.isAlive())) {
lista.remove(o);
}
}


viene lanciata l'eccezione: java.util.ConcurrentModificationException

Ho provato anche con gli Iterator, ma viene lanciata comunque java.util.ConcurrentModificationException

Sono sicuro che c'è un modo semplice per risolvere questo problema, ma al momento non mi viene proprio in mente.
Qualcuno ha un suggerimento?

astorcas
09-07-2010, 12:01
List<myObj> objectToRemove=new ArrayList<myObj>();
for(MyObj o: lista){
if(!(o.isAlive())) {
objectToRemove.add(o);
}
}
for(MyObj o: objectToRemove){
lista.remove(o);
}


oppure iteri su una copia della lista, che credo sia più dispendioso. Non so se ci sono soluzioni migliori.
Ciao

banryu79
09-07-2010, 12:02
Sono sicuro che c'è un modo semplice per risolvere questo problema, ma al momento non mi viene proprio in mente.
Qualcuno ha un suggerimento?
Con l'Iterator della lista, invocando il metodo 'remove' dell'Iterator, non quello della lista (altrimenti parte la ConcurrentModificationException).

Cioè così:

Iterator<MyObject> it = lista.iterator();
while (it.hasNext()) {
MyObject o = it.next();
if (! o.isAlive())
it.remove();
}


E con un piccolo refactoring volendo puoi arrivare a scrivere:

Iterator<MyObject> it = lista.iterator();
while (it.hasNext())
if (it.next().isNotAlive())
it.remove();


@EDIT:

Effettivamente volevo evitare di creare una lista di appoggio ogni volta che devo fare il controllo (che avviene ad ogni istante di tempo della mia simulazione), ma se non dovessero esserci altri modi...

Non è affatto neccessario creare una lista di appoggio, nella tua situazione.

Lim
09-07-2010, 12:08
Grazie per le celeri risposte!! :)

Effettivamente volevo evitare di creare una lista di appoggio ogni volta che devo fare il controllo (che avviene ad ogni istante di tempo della mia simulazione), ma se non dovessero esserci altri modi... :rolleyes:

Verifico anche il suggerimento di banryu79, è molto simile al tentativo che avevo fatto con gli iterator, ma non mi ero accorto che potevo dichiararlo così: Iterator<MyObject> ...., forse questa è la soluzione + rapida.

Lim
09-07-2010, 12:13
Si, perfetto!
Con gli Iterator è rapido ed indolore, funziona alla perfezione!!! :D

Grazie a tutti!!!

banryu79
09-07-2010, 12:16
Si, perfetto!
Con gli Iterator è rapido ed indolore, funziona alla perfezione!!! :D

Grazie a tutti!!!
Con questo:

for(MyObj o: lista){
if(!(o.isAlive())) {
lista.remove(o);
}
}

lancia l'eccezione perchè questa versione del for "dietro" le quinte usa un Iterator. E quando iteri una collezione tramite un iterator non puoi mutare la collezione se non tramite l'iterator stesso, pena la ConcurrentException.