^Matteo^ ha scritto:
la mia implementazione sarebbe stata questa:
public void mangiaMandariniSenzaSemi() {
for (Agrume a : agrumi) {
if (a instanceof Mandarino) {
Mandarino m = (Mandarino) a;
agrumi.removeIf(Mandarino -> m.hasSemi() == false);
}
}
}
questo codice elimina tutti i gli Elementi di tipo Mandarino, anche se non ne capisco il motivo.
La mia seconda implementazione, senza lambda (per una mia incomprensione di queste), è stata la seguente:
public void mangiaMandariniSenzaSemi() {
for (Agrume a : agrumi) {
if (a instanceof Mandarino && ((Mandarino)a).hasSemi()==false) {
agrumi.remove(a);
}
}
}
L'esecuzione di questo metodo porta ad un'eccezione (java.util.ConcurrentModificationException).
Nessuna delle due è giusta.
La seconda è proprio sbagliata. Durante la iterazione vai a fare un remove direttamente sulla collezione. Questa è la causa del ConcurrentModificationException.
Le collezioni standard (es. ArrayList) hanno un iteratore che ha un comportamento che si dice "fail-fast". Durante la iterazione con l'Iterator fornito dalla collezione, la collezione NON si può modificare. Con l'unica eccezione possibile del remove() del Iterator stesso (e non quello della collezione).
Tutto questo è ben documentato (es. nel javadoc del framework).
La prima non ha senso, fa "troppo".
^Matteo^ ha scritto:
Sono andato a sbirciare nell'esercizio del professore e c'è solo questa riga:
agrumi.removeIf(m -> (m instanceof Mandarino) && (!((Mandarino) m).hasSemi()));
Questo ha più senso.
Il removeIf() ha già DENTRO la iterazione sulla collezione!! E per ciascun elemento invoca il predicato che gli hai passato e in base al risultato del predicato elimina (nota: con il remove() del Iterator !) oppure no l'oggetto i-esimo.
Ecco perché un TUO ciclo sulla collezione dove usi il removeIf() semplicemente NON ha senso.
^Matteo^ ha scritto:
ciò che non capisco io è: perché scriviamo (m instanceof Mandarino) dentro la lambda e non fuori (naturalmente in un if)? Non si cambia l'interfaccia in BiPredicate, con quest'ultima implementazione? Non dovremmo fare un confronto del tipo ((Mandarino) m).hasSemi()==false) per stabilire che il valore di ritorno sia falso?
La collezione (non l'hai precisato) è sicuramente parametrizzata <Agrume>. Quindi Mandarino è un sotto-tipo e potrebbero (non lo so nel tuo caso) esserci altri sotto-tipi (es. Arancia).
Quindi è giusto/sensato testare prima se è un oggetto Mandarino e poi testare se non ha semi (se è questo che si vuole: eliminare "solo i Mandarini senza semi").
P.S. leggi sempre bene la documentazione:
default boolean removeIf(Predicate<? super E> filter)
Removes
all of the elements of this collection that satisfy the given predicate.