Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling remove in foreach loop in Java [duplicate]

In Java, is it legal to call remove on a collection when iterating through the collection using a foreach loop? For instance:

List<String> names = .... for (String name : names) {    // Do something    names.remove(name). } 

As an addendum, is it legal to remove items that have not been iterated over yet? For instance,

//Assume that the names list as duplicate entries List<String> names = .... for (String name : names) {     // Do something     while (names.remove(name)); } 
like image 390
Michael Bobick Avatar asked Jul 28 '09 20:07

Michael Bobick


People also ask

Can we remove an element by using forEach loop?

It is not recommended adding or removing elements from a list within a loop as an index of its elements, and the length of the list is changed. This might lead to the incorrect output, or java.

How do you remove while iterating?

The right way to remove objects from ArrayList while iterating over it is by using the Iterator's remove() method.

How do you remove an element from an array in Java?

To remove an element from an array, we first convert the array to an ArrayList and then use the 'remove' method of ArrayList to remove the element at a particular index. Once removed, we convert the ArrayList back to the array.


2 Answers

To safely remove from a collection while iterating over it you should use an Iterator.

For example:

List<String> names = .... Iterator<String> i = names.iterator(); while (i.hasNext()) {    String s = i.next(); // must be called before you can call i.remove()    // Do something    i.remove(); } 

From the Java Documentation :

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

Perhaps what is unclear to many novices is the fact that iterating over a list using the for/foreach constructs implicitly creates an iterator which is necessarily inaccessible. This info can be found here

like image 166
Mark Avatar answered Sep 22 '22 23:09

Mark


You don't want to do that. It can cause undefined behavior depending on the collection. You want to use an Iterator directly. Although the for each construct is syntactic sugar and is really using an iterator, it hides it from your code so you can't access it to call Iterator.remove.

The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.

Instead write your code:

List<String> names = .... Iterator<String> it = names.iterator(); while (it.hasNext()) {      String name = it.next();     // Do something     it.remove(); } 

Note that the code calls Iterator.remove, not List.remove.

Addendum:

Even if you are removing an element that has not been iterated over yet, you still don't want to modify the collection and then use the Iterator. It might modify the collection in a way that is surprising and affects future operations on the Iterator.

like image 26
Jared Oberhaus Avatar answered Sep 23 '22 23:09

Jared Oberhaus