By Michael Bobick


2009-07-28 20:39:07 8 Comments

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));
}

11 comments

@ktamlyn 2013-01-23 22:01:15

for (String name : new ArrayList<String>(names)) {
    // Do something
    names.remove(nameToRemove);
}

You clone the list names and iterate through the clone while you remove from the original list. A bit cleaner than the top answer.

@itzhar 2015-08-26 10:45:23

this supposed to be the first answer here...

@D3V 2015-12-28 14:54:29

Beware. For composite objects with no equals and hashCode method, it might just fail. However, marked answer safely removes it.

@SND 2017-12-15 07:53:31

Though short and clean, if performance/memory usage are an issue, it is worth to note that this solution runs in O(n²) and creates a copy of the original list, which requires memory and an operation depending on the type of the list. Using an iterator over a LinkedList you can bring complexity down to O(n).

@Mark 2009-07-28 20:43:38

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

@John Mellor 2012-03-07 15:18:05

Note that you must call i.next() before you can call i.remove(): docs.oracle.com/javase/6/docs/api/java/util/Iterator.html

@James P. 2012-05-12 22:02:29

I'm curious, why is this considered safe? Is the Iterator acting as middle man?

@Ethan Reesor 2012-06-20 20:22:36

I second James's question. What about that method is better?

@Mark 2012-06-25 11:22:42

To quote the Javadoc for 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." The iterator is acting as a middle man to safely perform the removal but allow the iteration to continue as expected.

@user1743310 2013-06-12 17:33:08

but worth noting that the remove() method is OPTIONAL on an iterator and will throw exceptions if it isn't implemented for your particular collection or JVM

@shareef 2013-06-17 09:39:45

FYI you can call it.next() in if statment instead of the sample above -- or you can do as the code above

@committedandroider 2015-03-22 06:42:48

I get the idea but based on isn't this all happening in one thread though? ConcurrentModificationException would make more sense if there was thread acting on the data structure.

@Mark 2015-03-22 22:18:37

@committedandroider From the Javadoc for ConcurrentModificationException Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

@committedandroider 2015-03-22 22:20:45

@Mark Thank you :)

@Sumit Gupta 2017-04-11 10:24:14

@Mark, But why java has designed only iterator to remove element. This could have been done for each loop also?

@ThmHarsh 2014-10-10 05:41:46

Use

.remove() of Interator or

Use

CopyOnWriteArrayList

@Yishai 2009-07-28 20:47:46

The java design of the "enhanced for loop" was to not expose the iterator to code, but the only way to safely remove an item is to access the iterator. So in this case you have to do it old school:

 for(Iterator<String> i = names.iterator(); i.hasNext();) {
       String name = i.next();
       //Do Something
       i.remove();
 }

If in the real code the enhanced for loop is really worth it, then you could add the items to a temporary collection and call removeAll on the list after the loop.

EDIT (re addendum): No, changing the list in any way outside the iterator.remove() method while iterating will cause problems. The only way around this is to use a CopyOnWriteArrayList, but that is really intended for concurrency issues.

The cheapest (in terms of lines of code) way to remove duplicates is to dump the list into a LinkedHashSet (and then back into a List if you need). This preserves insertion order while removing duplicates.

@Serafeim 2011-05-18 14:09:17

I didn't know about iterators, however here's what I was doing until today to remove elements from a list inside a loop:

List<String> names = .... 
for (i=names.size()-1;i>=0;i--) {    
    // Do something    
    names.remove(i);
} 

This is always working, and could be used in other languages or structs not supporting iterators.

@Mark McKenna 2011-11-01 13:01:35

Just as a side-note, that should work fine with any base-class list, but wouldn't be portable to more esoteric structures (like a self-sorting sequence, for example--in general, anywhere the ordinal for a given entry could change between list iterations).

@Jake Toronto 2014-09-24 04:46:36

Note: this works precisely because you're iterating backwords over the elements, so the indexes of the other remaining elements don't change when you remove the ith element. If you were looping from 0 to size()-1, and doing the remove, you'd see the issues mentioned in other answers. Nice job, though!

@DavidR 2016-11-29 02:21:40

This is just a horrible way to do. So many things can go wrong depending on the implementation of the List (or Set, etc.).

@WIll 2017-02-04 02:45:25

Such indexed based operations should only be conducted on lists whose elements can be accessed in O(1) constant time. If the list is not randomly accessible (does not implement RandomAccess) then you should use an iterator instead, as these types of collections usually take longer to retrieve an element at a specific index position, such as a LinkedList.

@forresthopkinsa 2017-10-18 19:45:41

As long as we're working with Java collections, where we do have iterators, there is no advantage to this method -- it only adds potential for really difficult debugging

@Serafeim 2017-10-18 20:49:03

The advantage of the above method is that you (or at least most people) don't have to google for "java iterator example" but can write it immediately, by memory.

@song 2012-02-09 08:51:44

It's better to use an Iterator when you want to remove element from a list

because the source code of remove is

if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
             numMoved);
elementData[--size] = null;

so ,if you remove an element from the list, the list will be restructure ,the other element's index will be changed, this can result something that you want to happened.

@bmcdonald 2011-11-14 16:57:57

Make sure this is not code smell. Is it possible to reverse the logic and be 'inclusive' rather than 'exclusive'?

List<String> names = ....
List<String> reducedNames = ....
for (String name : names) {
   // Do something
   if (conditionToIncludeMet)
       reducedNames.add(name);
}
return reducedNames;

The situation that led me to this page involved old code that looped through a List using indecies to remove elements from the List. I wanted to refactor it to use the foreach style.

It looped through an entire list of elements to verify which ones the user had permission to access, and removed the ones that didn't have permission from the list.

List<Service> services = ...
for (int i=0; i<services.size(); i++) {
    if (!isServicePermitted(user, services.get(i)))
         services.remove(i);
}

To reverse this and not use the remove:

List<Service> services = ...
List<Service> permittedServices = ...
for (Service service:services) {
    if (isServicePermitted(user, service))
         permittedServices.add(service);
}
return permittedServices;

When would "remove" be preferred? One consideration is if gien a large list or expensive "add", combined with only a few removed compared to the list size. It might be more efficient to only do a few removes rather than a great many adds. But in my case the situation did not merit such an optimization.

@Carsten 2011-01-05 14:24:18

  1. Try this 2. and change the condition to "WINTER" and you will wonder:
public static void main(String[] args) {
  Season.add("Frühling");
  Season.add("Sommer");
  Season.add("Herbst");
  Season.add("WINTER");
  for (String s : Season) {
   if(!s.equals("Sommer")) {
    System.out.println(s);
    continue;
   }
   Season.remove("Frühling");
  }
 }

@Chathuranga Withana 2010-12-10 11:52:34

Yes you can use the for-each loop, To do that you have to maintain a separate list to hold removing items and then remove that list from names list using removeAll() method,

List<String> names = ....

// introduce a separate list to hold removing items
List<String> toRemove= new ArrayList<String>();

for (String name : names) {
   // Do something: perform conditional checks
   toRemove.add(name);
}    
names.removeAll(toRemove);

// now names list holds expected values

@Varun Mehta 2011-01-25 03:31:19

Why add the overhead of another list ?

@Chathuranga Withana 2011-03-19 18:44:15

Since the for-each loop hides the iterator, you cannot call the remove() directly. So in order to remove items from a for-each loop while iterating through it, have to maintain a separate list. That list will maintain references to the items to be removed...

@mmatloka 2012-01-04 13:39:08

Its very slow. removeAll 1. runs contains() on every toRemove element 2. then runs remove() which has to find element index so need to again look through whole list.

@user1743310 2013-06-12 17:36:16

this isn't calling remove() in a foreach loop

@sanity 2009-07-28 23:25:51

Those saying that you can't safely remove an item from a collection except through the Iterator aren't quite correct, you can do it safely using one of the concurrent collections such as ConcurrentHashMap.

@Jared Oberhaus 2009-07-28 20:43:15

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.

Related Questions

Sponsored Content

53 Answered Questions

[SOLVED] Creating a memory leak with Java

33 Answered Questions

[SOLVED] How do I loop through or enumerate a JavaScript object?

38 Answered Questions

[SOLVED] Loop through an array in JavaScript

77 Answered Questions

[SOLVED] Is Java "pass-by-reference" or "pass-by-value"?

31 Answered Questions

[SOLVED] How to break out of nested loops in Java?

  • 2009-05-20 09:07:43
  • boutta
  • 965461 View
  • 1579 Score
  • 31 Answer
  • Tags:   java loops

39 Answered Questions

[SOLVED] JavaScript closure inside loops – simple practical example

26 Answered Questions

[SOLVED] How does the Java 'for each' loop work?

21 Answered Questions

[SOLVED] Accessing the index in 'for' loops?

  • 2009-02-06 22:47:54
  • Joan Venge
  • 1464015 View
  • 2692 Score
  • 21 Answer
  • Tags:   python loops list

7 Answered Questions

[SOLVED] How does PHP 'foreach' actually work?

5 Answered Questions

[SOLVED] Is there a reason for C#'s reuse of the variable in a foreach?

Sponsored Content