# Objekt aus Liste entfernen



## javac- (9. Jun 2016)

Hallo,

ich füge in eine Liste Auto folgendermaßen hinzu:


```
public void autohinzufuegen(){ // 5 Autos in die Liste hinzufügen
 
Random rnd = new Random();
     
  for(int i=0; i<5; i++){
       Auto a1 = new Auto();
       int x = 1+rnd.nextInt(10000);//Zufälligen Wert setzen
       a1.setWert(x);
       this.list.add(a1);
   
     }
   }
```

und nun will ich alle Autos die mehr als 2000€ Wert sind wieder löschen


```
public  void autoRemoveByValue(){
 
     for(Auto current : list){ // Hier Zeile 41 - aus der Fehlermeldung siehe unten
   
       if(current.getWert()>2000){
     
         System.out.println("Auto mit Wert "+current.getWert() +" wurde gelöscht ");
         list.remove(current);
       }
     }
```

Fehlermeldung:
"
Exception in thread "main" java.util.ConcurrentModificationException
   at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
   at java.util.ArrayList$Itr.next(Unknown Source)
   at löschen.Auto.autoRemoveByValue(Auto.java:41)
   at löschen.Main.main(Main.java:22)"

Wenn ich das ganze mit einer for-Schleife mit Index mache, also


```
for(int i=0; i<list.size(); i++){
....list.remove(i);
```

funktionierts. Was ist oben falsch? Man darf doch ganze Objekte übergeben wenn man diese aus der Liste löschen will oder?

Danke


----------



## Thallius (9. Jun 2016)

Du darfst eine Collection durch die du mit einem iterator gehst nicht ändern. Deshalb ist der zweite weg der richtige.

Gruß

Claus


----------



## Xyz1 (9. Jun 2016)

Klar darf er das. Der 2. ist semantisch falsch.

fori benutzen.


----------



## javac- (9. Jun 2016)

also wenn ich es ohne Schleife mache funktionierts:


```
ArrayList <Auto>l1 = new ArrayList<Auto>();
Auto a1 = new Auto();

     l1.add(a1);
     l1.remove(a1);
```


----------



## JCODA (9. Jun 2016)

Thallius hat gesagt.:


> Du darfst eine Collection durch die du mit einem iterator gehst nicht ändern. Deshalb ist der zweite weg der richtige.
> 
> Gruß
> 
> Claus


"Richtig" wird er aber erst wenn er den Index noch um eins verringert, wenn etwas gelöscht wird.


----------



## Xyz1 (9. Jun 2016)

JCODA hat gesagt.:


> "Richtig" wird er aber erst wenn er den Index noch um eins verringert, wenn etwas gelöscht wird.



Ich sag doch schon, dass es semantisch falsch ist - und ansonsten ugly.

Korrekt:

```
/**
 * @author DerWissende on 06/09/2016
 */
public class Temp {

    public static void main(String[] args) {
        ArrayList<Auto> ala = new ArrayList<Auto>();
        for (int i = 0; i < 10; i++) {
            Auto a = new Auto();
            a.setWert(1 + (int) (Math.random() * 10000.0D));
            ala.add(a);
        }
        for (Iterator<Auto> iterator = ala.iterator(); iterator.hasNext();) {
            Auto next = iterator.next();
            if (next.getWert() > 2000) {
                iterator.remove();
            }
        }
        for (Auto a : ala) {
            System.out.println("a = " + a);
        }
    }

}

class Auto {

    int wert;

    int getWert() {
        return wert;
    }

    void setWert(int wert) {
        this.wert = wert;
    }

    @Override
    public String toString() {
        return "Auto{" + "wert=" + wert + '}';
    }

}
```

Ein Danke/Gefällt mir zeigt mir den Erfolg meines Beitrag. Also jetzt da darauf klicken.


----------



## javac- (9. Jun 2016)

Danke ;-)


----------



## mrBrown (9. Jun 2016)

Oder die eleganteste Lösung 


```
list.removeIf(auto -> auto.getWert() > 2000);
```


----------



## Xyz1 (10. Jun 2016)

Aber aber, das ist nicht prozedural und würde von mir abgelehnt werden. 
Auf son neumodischen Krams setzten wir aus unterschiedlichsten Grünen NICHT.
Außerdem ist das kein adäquate Antwort auf die Frage des TE.


----------



## thecain (10. Jun 2016)

JCODA hat gesagt.:


> "Richtig" wird er aber erst wenn er den Index noch um eins verringert, wenn etwas gelöscht wird.


Oder die liste von hinten durchiteriert.


----------



## Xyz1 (10. Jun 2016)

thecain hat gesagt.:


> Oder die liste von hinten durchiteriert.



ArrayList nimmt eh Verschiebungen vor. Am geeignetsten tue ich mich schwer mit zu sagen, weil ich den haarkleinsten Anwendungsfall nicht kenne, aber `LinkedList` ist auch mal ein Blick wert zu riskieren. 

Und dieses per Index/Indices/Indexes drüberlaufen... würd nicht durchs peer/pair review kommen, aber vielleicht für ihn zum Lernen ganz gut..


----------



## Neumi5694 (11. Jun 2016)

Wenn du mit Indizes arbeiten willst, dann lass von hinten nach vorne durchlaufen, sonst überspringst du beim Löschen das nächste Element, falls du in dem Moment nicht auch den Index um 1 verringerst.
Während des Durchlaufens eines Iterators darfst du nichts löschen, sonst kriegst du eben diese Meldung.
Ein Workaround wäre, eine 2. Liste anzulegen, die zu löschenden Elemente dort zwischenzuspeichern und hinterher gesammelt (z.B. mit removeAll()) aus der ersten Liste zu löschen.
removeIf ist natürlich am elegantesten.


----------



## Flown (13. Jun 2016)

Nur als Information: `Collection::removeIf` macht genau das, was @DerWissende geschrieben hat und ist in diesem Fall, das Eleganteste und Schnellste.

Codeauszug aus JDK1.8_92:

```
default boolean removeIf(Predicate<? super E> filter) {
  Objects.requireNonNull(filter);
  boolean removed = false;
  final Iterator<E> each = iterator();
  while (each.hasNext()) {
      if (filter.test(each.next())) {
          each.remove();
          removed = true;
      }
  }
  return removed;
}
```


----------



## Thallius (13. Jun 2016)

Mag sein das Du das elegant findest aber für mich ist das schwer lesbar.

Ich finde ein


```
int index = 0;
while(index < list.size())
{
    Auto auto = list.get(index)
    if(auto.currentWert > 2000)
        list.remove(auto);
    else
        index++;
}
```

wesentlich einfacher und leserlicher.

Gruß

Claus


----------



## mrBrown (13. Jun 2016)

Man muss aber schon ein bisschen masochistisch veranlagt sein, um 'nen 9-Zeiler mit grad mal 2 relevanten Zeilen eleganter zu finden als 'nen Einzeiler 



DerWissende hat gesagt.:


> Auf son neumodischen Krams setzten wir aus unterschiedlichsten Grünen NICHT.


Aus welchen Gründen denn? (Außer "neumodischer Kram" und "nicht prozedural" und "zu wenig Zeilen!11elf")


----------



## Xyz1 (13. Jun 2016)

Wir bleiben nun mal bei einem Programmierparadigma. Dass Thallius es nicht "besser" formulieren kann, liegt daran, dass es nicht besser zu programmieren ist als meins.

Aber noch mal, hier kommt's wie immer auf den Fall der Anwendung an und die geschickteste Wahl der data structure. DENN, wie gesagt, `ArrayList` nimmt gerne (also immer) Verschiebungen mindestens der Hälfte der Elemente vor.


----------



## flopalko (13. Jun 2016)

DerWissende hat gesagt.:


> [...]`ArrayList` nimmt gerne (also immer) Verschiebungen mindestens der Hälfte der Elemente vor.


Das stimmt einfach nicht! Wenn du zum Beispiel das letzte Element löscht kommt es zu gar keiner Verschiebung.


----------



## Xyz1 (13. Jun 2016)

Und was passiert, wenn du das Mittlere löschst? Eben.


----------



## flopalko (13. Jun 2016)

Ja beim mittleren stimmt es auch. Wenn du das erste löscht verschiebt er sogar alle anderen :O
Trotzdem stimmt deine Aussage, dass ArrayList immer mindestens die Hälfte der Elemente verschiebt nicht! Gegenbeispiel: das letzte Element.
Wenn du gesagt hättest im Average Case werden die Hälfte der Elemente verschoben hättest du recht, so ist es absoluter Blödsinn.


----------



## Xyz1 (13. Jun 2016)

Soll ich einen Anfänger jetzt mit Amortisierung für den Average ärgern?

Dann stimmt meine Aussage eben nicht...


----------



## flopalko (13. Jun 2016)

Nein nicht ärgern, ihm aber auch keinen Blödsinn sagen.
Vor allem kann man es verständlich sagen, und zwar statt immer durchschnittlich sagen, dann stimmt's


----------

