1295

We all know you can't do the following because of ConcurrentModificationException:

for (Object i : l) {
    if (condition(i)) {
        l.remove(i);
    }
}

But this apparently works sometimes, but not always. Here's some specific code:

public static void main(String[] args) {
    Collection<Integer> l = new ArrayList<>();

    for (int i = 0; i < 10; ++i) {
        l.add(4);
        l.add(5);
        l.add(6);
    }

    for (int i : l) {
        if (i == 5) {
            l.remove(i);
        }
    }

    System.out.println(l);
}

This, of course, results in:

Exception in thread "main" java.util.ConcurrentModificationException

Even though multiple threads aren't doing it. Anyway.

What's the best solution to this problem? How can I remove an item from the collection in a loop without throwing this exception?

I'm also using an arbitrary Collection here, not necessarily an ArrayList, so you can't rely on get.

Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • 1
    Note to readers: do have a read of http://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html, it may have an easier way to achieve what you want to do. – GKFX May 05 '17 at 08:38

31 Answers31

1670

Iterator.remove() is safe, you can use it like this:

List<String> list = new ArrayList<>();

// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
//     Iterator<String> iterator = list.iterator();
//     while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String string = iterator.next();
    if (string.isEmpty()) {
        // Remove the current element from the iterator and the list.
        iterator.remove();
    }
}

Note that Iterator.remove() is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.

Source: docs.oracle > The Collection Interface


And similarly, if you have a ListIterator and want to add items, you can use ListIterator#add, for the same reason you can use Iterator#remove — it's designed to allow it.


In your case you tried to remove from a list, but the same restriction applies if trying to put into a Map while iterating its content.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Bill K
  • 62,186
  • 18
  • 105
  • 157
  • 21
    What if you want to remove an element other than the element returned in the current iteration? – Eugen Apr 22 '13 at 09:51
  • 2
    You have to use the .remove in the iterator and that is only able to remove the current element, so no :) – Bill K Apr 22 '13 at 18:00
  • 1
    Be aware that this is slower compared to using ConcurrentLinkedDeque or CopyOnWriteArrayList (at least in my case) – Dan Oct 24 '14 at 01:43
  • @Josh It does work fine for me. Just using it now for a collection of WebElement objects. –  Aug 20 '15 at 12:44
  • 1
    Is it not possible to put the `iterator.next()` call in the for-loop? If not, can someone explain why? – Blake Apr 12 '16 at 13:22
  • It is possible to put another `iterator.next()` call in the for-loop, but you will also have to add another check using `iterator.hasNext()` to make sure you even have another element to retrieve. – gaoagong Jul 07 '16 at 17:12
  • Can anyone comment how good is this way of deleting an element from a list if my list has a million elements and there are lots of possibilities of running out of java heap space? – Gopal1216 Jul 12 '17 at 16:02
  • If it is a linked list you should be great. If it is an array list then you are in trouble – Bill K Jul 12 '17 at 16:05
  • Iterator.remove() is an optional operation, so it is not necessarily safe (or implemented) for all container iterators – Gonen I Jul 25 '18 at 16:57
  • 1
    @GonenI It's implemented for all iterators from collections which aren't immutable. `List.add` is "optional" in that same sense too, but you wouldn't say it's "unsafe" to add to a list. – Radiodef Aug 09 '18 at 00:33
  • 1
    As of Java 8, this approach is built-in as `l.removeIf(i -> condition(i));`, see https://stackoverflow.com/a/29187813/929708 – JJ Brown Dec 02 '19 at 22:54
  • I'm using this approach and still get a `ConcurrentModificationException`. Can someone explain to me why this is? – Allix Jul 07 '20 at 15:00
  • @bill-k Why you verify if the string is empty? `if (string.isEmpty())` – Quimbo Jan 13 '21 at 23:52
  • @Quimbo it is just a condition...the example shown is to remove empty strings. I didn’t write it, so many people have edited this question—look at the history for fun. Personally I liked my original answer, it was like two lines, but I guess it’s important to be as clear as possible with such a popular answer – Bill K Jan 16 '21 at 19:26
  • Is this still the recommended way in 2021? – marticztn Aug 10 '21 at 23:32
  • @marticztn If you need to remove an object (or objects) from a collection inside a loop, then yes, however these days I would personally use the streaming api and filter it as the first step. This leaves the collection untouched (So it doesn't solve the "Remove it" problem, but it does let you use the collection without that data), and you could collect it into a new collection perhaps. This would be way less performant because it would make a copy of the entire collection, however the streaming API has some big benefits when it comes to threading--I guess it's up to you and your use case. – Bill K Aug 13 '21 at 00:16
  • **Iterators** are not always helpful when another thread also modifies the collection. I had tried many ways but then realized traversing the collection manually is much safer (backward for removal) – Saeed Ir Nov 23 '22 at 07:14
  • @SaeedIr If you are reading from a different thread than you are modifying from, you should be using one of the high-performance threadsafe collecitons instead. You cannot ever trust "Manual" synchronization of threads, you must use java constructs to lock out other threads while you are modifying one--because of multiple CPUs and caching, how a normal collection works while being manipulated by another thread is not guaranteed. – Bill K Nov 30 '22 at 22:27
358

This works:

Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
    if (iter.next() == 5) {
        iter.remove();
    }
}

I assumed that since a foreach loop is syntactic sugar for iterating, using an iterator wouldn't help... but it gives you this .remove() functionality.

Lii
  • 11,553
  • 8
  • 64
  • 88
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • 48
    foreach loop *is* syntactic sugar for iterating. However as you pointed out, you need to call remove on the iterator - which foreach doesn't give you access to. Hence the reason why you can't remove in a foreach loop (even though you *are* actually using an iterator under the hood) – madlep Oct 21 '08 at 23:30
  • 36
    +1 for example code to use iter.remove() in context, which Bill K's answer does not [directly] have. – Eddified Oct 03 '12 at 17:01
242

With Java 8 you can use the new removeIf method. Applied to your example:

Collection<Integer> coll = new ArrayList<>();
//populate

coll.removeIf(i -> i == 5);

A simple test as example:

    @Test
    public void testRemoveIfOneList() {
        List<String> outer = new ArrayList<>();
        outer.add("one");
        outer.add("two");
        outer.add("three");

        outer.removeIf(o -> o.length() == 3);

        assertEquals(1, outer.size());
    }

It even works when you compare two lists and want to remove from both.

    @Test
    public void testRemoveIfTwoLists() {
        List<String> outer = new ArrayList<>();
        outer.add("one");
        outer.add("two");
        outer.add("three");
        List<String> inner = new ArrayList<>();
        inner.addAll(outer);

        // first, it removes from inner, and if anything is removed, then removeIf() returns true,
        // leading to removing from outer
        outer.removeIf(o -> inner.removeIf(i -> i.equals(o)));

        assertEquals(0, outer.size());
        assertEquals(0, inner.size());
    }

However, if one of the list has duplicates, make sure it's iterated in the inner loop, because for inner list, it will remove all elements meeting the criteria, but for outer list, when any element is removed, it will return immediately and stops checking.

This test will fail:

    @Test
    public void testRemoveIfTwoListsInnerHasDuplicates() {
        List<String> outer = new ArrayList<>();
        outer.add("one");
        outer.add("one");
        outer.add("two");
        outer.add("two");
        outer.add("three");
        outer.add("three");
        List<String> inner = new ArrayList<>();
        inner.addAll(outer); // both have duplicates

        // remove all elements from inner(executed twice), then remove from outer
        // but only once! if anything is removed, it will return immediately!!
        outer.removeIf(o -> inner.removeIf(i -> i.equals(o)));

        assertEquals(0, inner.size()); // pass, inner all removed
        assertEquals(0, outer.size()); // will fail, outer has size = 3
    }
WesternGun
  • 11,303
  • 6
  • 88
  • 157
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 3
    Ooooo! I was hoping something in Java 8 or 9 might help. This still seems rather verbose to me, but I still like it. – James T Snell Sep 23 '15 at 18:25
  • Is implementing equals() recommended in this case too? – Anmol Gupta Dec 11 '15 at 08:57
  • by the way `removeIf` uses `Iterator` and `while` loop. You can see it at java 8 `java.util.Collection.java` – omerhakanbilici Oct 31 '16 at 14:10
  • 3
    @omerhakanbilici Some implementations like `ArrayList` override it for performance reasons. The one you are referring to is only the default implementation. – Didier L Mar 31 '17 at 08:33
  • @AnmolGupta: No, `equals` is not used at all here, so it doesn't have to be implemented. (But of course, if you use `equals` in your test then it has to be implemented the way you want it.) – Lii Jan 03 '19 at 10:31
  • This should be the accepted answer now, this will be applicable and desirable for most people looking at the answers here. – Anupam Nov 19 '20 at 00:05
44

Since the question has been already answered i.e. the best way is to use the remove method of the iterator object, I would go into the specifics of the place where the error "java.util.ConcurrentModificationException" is thrown.

Every collection class has a private class which implements the Iterator interface and provides methods like next(), remove() and hasNext().

The code for next looks something like this...

public E next() {
    checkForComodification();
    try {
        E next = get(cursor);
        lastRet = cursor++;
        return next;
    } catch(IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
    }
}

Here the method checkForComodification is implemented as

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

So, as you can see, if you explicitly try to remove an element from the collection. It results in modCount getting different from expectedModCount, resulting in the exception ConcurrentModificationException.

akhil_mittal
  • 23,309
  • 7
  • 96
  • 95
Ashish
  • 3,028
  • 5
  • 28
  • 35
  • 1
    Very interesting. Thank you! I often don't call remove() myself, I instead favour clearing the collection after iterating through it. Not to say that's a good pattern, just what I've been doing lately. – James T Snell Sep 23 '15 at 18:27
28

You can either use the iterator directly like you mentioned, or else keep a second collection and add each item you want to remove to the new collection, then removeAll at the end. This allows you to keep using the type-safety of the for-each loop at the cost of increased memory use and cpu time (shouldn't be a huge problem unless you have really, really big lists or a really old computer)

public static void main(String[] args)
{
    Collection<Integer> l = new ArrayList<Integer>();
    Collection<Integer> itemsToRemove = new ArrayList<>();
    for (int i=0; i < 10; i++) {
        l.add(Integer.of(4));
        l.add(Integer.of(5));
        l.add(Integer.of(6));
    }
    for (Integer i : l)
    {
        if (i.intValue() == 5) {
            itemsToRemove.add(i);
        }
    }

    l.removeAll(itemsToRemove);
    System.out.println(l);
}
MC Emperor
  • 22,334
  • 15
  • 80
  • 130
RodeoClown
  • 13,338
  • 13
  • 52
  • 56
  • 7
    this is what i normally do, but the explicit iterator is a more elgant solution i feel. – Claudiu Oct 21 '08 at 23:51
  • 1
    Fair enough, as long as you aren't doing anything else with the iterator - having it exposed makes it easier to do things like call .next() twice per loop etc. Not a huge problem, but can cause issues if you are doing anything more complicated than just running through a list to delete entries. – RodeoClown Oct 21 '08 at 23:58
  • @RodeoClown: in the original question, Claudiu is removing from the Collection, not the iterator. – matt b Oct 22 '08 at 14:29
  • 1
    Removing from the iterator removes from the underlying collection... but what I was saying in the last comment is that if you are doing anything more complicated than just looking for deletes in the loop (like processing correct data) using the iterator can make some errors easier to make. – RodeoClown Oct 22 '08 at 18:35
  • If it is a simple delete values that aren't needed and the loop is only doing that one thing, using the iterator directly and calling .remove() is absolutely fine. – RodeoClown Oct 22 '08 at 18:36
  • using Iterator.remove() only works on the current value provided by the iterator. If you have some condition in your loop that requires removal of some _other_ member of the collection, then RodeoClown's solution is the way to go. – PMorganCA May 16 '13 at 14:46
19

In such cases a common trick is (was?) to go backwards:

for(int i = l.size() - 1; i >= 0; i --) {
  if (l.get(i) == 5) {
    l.remove(i);
  }
}

That said, I'm more than happy that you have better ways in Java 8, e.g. removeIf or filter on streams.

Landei
  • 54,104
  • 13
  • 100
  • 195
17

Same answer as Claudius with a for loop:

for (Iterator<Object> it = objects.iterator(); it.hasNext();) {
    Object object = it.next();
    if (test) {
        it.remove();
    }
}
Community
  • 1
  • 1
Antzi
  • 12,831
  • 7
  • 48
  • 74
12

With Eclipse Collections, the method removeIf defined on MutableCollection will work:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

With Java 8 Lambda syntax this can be written as follows:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

The call to Predicates.cast() is necessary here because a default removeIf method was added on the java.util.Collection interface in Java 8.

Note: I am a committer for Eclipse Collections.

Donald Raab
  • 6,458
  • 2
  • 36
  • 44
11

Make a copy of existing list and iterate over new copy.

for (String str : new ArrayList<String>(listOfStr))     
{
    listOfStr.remove(/* object reference or index */);
}
Priyank Doshi
  • 12,895
  • 18
  • 59
  • 82
  • 20
    Making a copy sounds like a waste of resources. – Antzi Aug 21 '13 at 12:35
  • 4
    @Antzi That depends on the size of the list and the density of the objects within. Still a valuable and valid solution. – mre May 04 '16 at 14:14
  • I have been using this method. It takes a bit more resource, but much more flexible and clear. – Tao Zhang Feb 07 '19 at 23:34
  • This is a good solution when you are not intending to remove objects inside the loop itself, but they are rather "randomly" removed from other threads (e.g. network operations updating data). If you find yourself doing these copies a lot there is even a java implementation doing exactly this: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CopyOnWriteArrayList.html – A1m Oct 26 '19 at 03:15
  • Making a copy of the list is what they are typically doing with listeners on Android. It's a valid solution for small lists. – Slion Feb 08 '21 at 16:50
10

With a traditional for loop

ArrayList<String> myArray = new ArrayList<>();

for (int i = 0; i < myArray.size(); ) {
    String text = myArray.get(i);
    if (someCondition(text))
        myArray.remove(i);
    else
        i++;   
}
from56
  • 3,976
  • 2
  • 13
  • 23
  • 1
    Ah, so its really just the _enhanced_-for-loop that throws the Exception. – cellepo Dec 20 '18 at 00:11
  • FWIW - same code would still work after modified to increment `i++` in the loop guard rather than within loop body. – cellepo Dec 20 '18 at 00:11
  • Correction ^: That is if the `i++` incrementing were not conditional - I see now that's why you do it in the body :) – cellepo Dec 20 '18 at 00:23
10

People are asserting one can't remove from a Collection being iterated by a foreach loop. I just wanted to point out that is technically incorrect and describe exactly (I know the OP's question is so advanced as to obviate knowing this) the code behind that assumption:

for (TouchableObj obj : untouchedSet) {  // <--- This is where ConcurrentModificationException strikes
    if (obj.isTouched()) {
        untouchedSet.remove(obj);
        touchedSt.add(obj);
        break;  // this is key to avoiding returning to the foreach
    }
}

It isn't that you can't remove from the iterated Colletion rather that you can't then continue iteration once you do. Hence the break in the code above.

Apologies if this answer is a somewhat specialist use-case and more suited to the original thread I arrived here from, that one is marked as a duplicate (despite this thread appearing more nuanced) of this and locked.

Miss Chanandler Bong
  • 4,081
  • 10
  • 26
  • 36
John
  • 6,433
  • 7
  • 47
  • 82
4

ConcurrentHashMap or ConcurrentLinkedQueue or ConcurrentSkipListMap may be another option, because they will never throw any ConcurrentModificationException, even if you remove or add item.

Yessy
  • 1,172
  • 1
  • 8
  • 13
  • Yep, and note that those are all in `java.util.concurrent` package. Some other similar/common-use-case classes from that package are `CopyOnWriteArrayList ` & `CopyOnWriteArraySet ` [but not limited to those]. – cellepo Nov 19 '18 at 03:52
  • Actually, I just learned that although those data structure Objects _avoid_ `ConcurrentModificationException`, using them in an _enhanced_-for-loop can still cause indexing problems (i.e: still skipping elements, or `IndexOutOfBoundsException`...) – cellepo Dec 20 '18 at 01:13
4

Another way is to use a copy of your arrayList just for iteration:

List<Object> l = ...
    
List<Object> iterationList = ImmutableList.copyOf(l);
    
for (Object curr : iterationList) {
    if (condition(curr)) {
        l.remove(curr);
    }
}
Nestor Milyaev
  • 5,845
  • 2
  • 35
  • 51
  • 2
    Note: `i` isn't a `index` but instead the object. Maybe calling it `obj` would be more fitting. – luckydonald Mar 29 '19 at 12:05
  • 1
    Was already suggested above back in 2012:https://stackoverflow.com/a/11201224/3969362 Making a copy of the list is what they are typically doing with listeners on Android. It's a valid solution for small lists. – Slion Feb 08 '21 at 16:47
3

A ListIterator allows you to add or remove items in the list. Suppose you have a list of Car objects:

List<Car> cars = ArrayList<>();
// add cars here...

for (ListIterator<Car> carIterator = cars.listIterator();  carIterator.hasNext(); )
{
   if (<some-condition>)
   { 
      carIterator().remove()
   }
   else if (<some-other-condition>)
   { 
      carIterator().add(aNewCar);
   }
}
james.garriss
  • 12,959
  • 7
  • 83
  • 96
  • The additional methods in the [ListIterator](https://docs.oracle.com/javase/8/docs/api/java/util/ListIterator.html) interface (extension of Iterator) are interesting - particularly its `previous` method. – cellepo Dec 19 '18 at 23:58
2

Now, You can remove with the following code

l.removeIf(current -> current == 5);
Adil Karaöz
  • 216
  • 1
  • 11
1

I know this question is too old to be about Java 8, but for those using Java 8 you can easily use removeIf():

Collection<Integer> l = new ArrayList<Integer>();

for (int i=0; i < 10; ++i) {
    l.add(new Integer(4));
    l.add(new Integer(5));
    l.add(new Integer(6));
}

l.removeIf(i -> i.intValue() == 5);
pedram bashiri
  • 1,286
  • 15
  • 21
1

Java Concurrent Modification Exception

  1. Single thread
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String value = iter.next()
    if (value == "A") {
        list.remove(it.next()); //throws ConcurrentModificationException
    }
}

Solution: iterator remove() method

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String value = iter.next()
    if (value == "A") {
        it.remove()
    }
}
  1. Multi thread
  • copy/convert and iterate over another one collection. For small collections
  • synchronize[About]
  • thread safe collection[About]
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
0

I have a suggestion for the problem above. No need of secondary list or any extra time. Please find an example which would do the same stuff but in a different way.

//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
    Object r = list.get(index);
    if( state ) {
        list.remove(index);
        index = 0;
        continue;
    }
    index += 1;
}

This would avoid the Concurrency Exception.

svick
  • 236,525
  • 50
  • 385
  • 514
Nandhan Thiravia
  • 360
  • 2
  • 12
  • 2
    The question explicitly states, that the OP is not necessary using `ArrayList` and thus cannot rely on `get()`. Otherwise probably a good approach, though. – kaskelotti Apr 13 '14 at 11:09
  • (Clarification ^) OP is using an arbitrary`Collection` - `Collection` interface does not include `get`. (Although FWIW `List` interface does include 'get'). – cellepo Dec 19 '18 at 22:31
  • I just added a separate, more detailed Answer here also for `while`-looping a `List`. But +1 for this Answer because it came first. – cellepo Dec 19 '18 at 23:44
0
for (Integer i : l)
{
    if (i.intValue() == 5){
            itemsToRemove.add(i);
            break;
    }
}

The catch is the after removing the element from the list if you skip the internal iterator.next() call. it still works! Though I dont propose to write code like this it helps to understand the concept behind it :-)

Cheers!

0

The best way (recommended) is use of java.util.concurrent package. By using this package you can easily avoid this exception. Refer Modified Code:

public static void main(String[] args) {
    Collection<Integer> l = new CopyOnWriteArrayList<Integer>();
    
    for (int i=0; i < 10; ++i) {
        l.add(new Integer(4));
        l.add(new Integer(5));
        l.add(new Integer(6));
    }
    
    for (Integer i : l) {
        if (i.intValue() == 5) {
            l.remove(i);
        }
    }
    
    System.out.println(l);
}
user207421
  • 305,947
  • 44
  • 307
  • 483
jagdish khetre
  • 1,381
  • 2
  • 8
  • 15
  • Did you take into account the performance hit? Each time you "write" to this structure, it's contents will be copied to a new object. All this is bad for performance. – Shankha057 Jul 29 '20 at 12:16
  • It isn't the best way and it isn't recommended. Don't use quote formatting for text that isn't quoted. If it is quoted, provide a citation. – user207421 Apr 01 '22 at 06:18
0

Example of thread safe collection modification:

public class Example {
    private final List<String> queue = Collections.synchronizedList(new ArrayList<String>());

    public void removeFromQueue() {
        synchronized (queue) {
            Iterator<String> iterator = queue.iterator();
            String string = iterator.next();
            if (string.isEmpty()) {
                iterator.remove();
            }
        }
    }
}
Yazon2006
  • 3,684
  • 3
  • 25
  • 36
0

I know this question assumes just a Collection, and not more specifically any List. But for those reading this question who are indeed working with a List reference, you can avoid ConcurrentModificationException with a while-loop (while modifying within it) instead if you want to avoid Iterator (either if you want to avoid it in general, or avoid it specifically to achieve a looping order different from start-to-end stopping at each element [which I believe is the only order Iterator itself can do]):

*Update: See comments below that clarify the analogous is also achievable with the traditional-for-loop.

final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
    list.add(i);
}

int i = 1;
while(i < list.size()){
    if(list.get(i) % 2 == 0){
        list.remove(i++);

    } else {
        i += 2;
    }
}

No ConcurrentModificationException from that code.

There we see looping not start at the beginning, and not stop at every element (which I believe Iterator itself can't do).

FWIW we also see get being called on list, which could not be done if its reference was just Collection (instead of the more specific List-type of Collection) - List interface includes get, but Collection interface does not. If not for that difference, then the list reference could instead be a Collection [and therefore technically this Answer would then be a direct Answer, instead of a tangential Answer].

FWIWW same code still works after modified to start at beginning at stop at every element (just like Iterator order):

final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
    list.add(i);
}

int i = 0;
while(i < list.size()){
    if(list.get(i) % 2 == 0){
        list.remove(i);

    } else {
        ++i;
    }
}
cellepo
  • 4,001
  • 2
  • 38
  • 57
  • This still requires very careful calculation of indicies to remove, however. – OneCricketeer Dec 19 '18 at 23:56
  • Also, this is just a more detailed explanation of this answer https://stackoverflow.com/a/43441822/2308683 – OneCricketeer Dec 19 '18 at 23:57
  • Good to know - thanks! That other Answer helped me understand that it's the _enhanced_-for-loop that would throw `ConcurrentModificationException`, but _not_ the _traditional_-for-loop (which the other Answer uses) - not realizing that before is why I was motivated to write this Answer (I erroneously thought then that it was _all_ for-loops that would throw the Exception). – cellepo Dec 20 '18 at 00:29
0

One solution could be to rotate the list and remove the first element to avoid the ConcurrentModificationException or IndexOutOfBoundsException

int n = list.size();
for(int j=0;j<n;j++){
    //you can also put a condition before remove
    list.remove(0);
    Collections.rotate(list, 1);
}
Collections.rotate(list, -1);
Rahul Vala
  • 695
  • 8
  • 17
0

Try this one (removes all elements in the list that equal i):

for (Object i : l) {
    if (condition(i)) {
        l = (l.stream().filter((a) -> a != i)).collect(Collectors.toList());
    }
}
Oleg Tatarchuk
  • 101
  • 1
  • 3
0

You can use a while loop.

Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
    Map.Entry<String, String> entry = iterator.next();
    if(entry.getKey().equals("test")) {
        iterator.remove();
    } 
}
Oguzhan Cevik
  • 638
  • 8
  • 18
0

I ended up with this ConcurrentModificationException, while iterating the list using stream().map() method. However the for(:) did not throw the exception while iterating and modifying the the list.

Here is code snippet , if its of help to anyone: here I'm iterating on a ArrayList<BuildEntity> , and modifying it using the list.remove(obj)

 for(BuildEntity build : uniqueBuildEntities){
            if(build!=null){
                if(isBuildCrashedWithErrors(build)){
                    log.info("The following build crashed with errors ,  will not be persisted -> \n{}"
                            ,build.getBuildUrl());
                    uniqueBuildEntities.remove(build);
                    if (uniqueBuildEntities.isEmpty()) return  EMPTY_LIST;
                }
            }
        }
        if(uniqueBuildEntities.size()>0) {
            dbEntries.addAll(uniqueBuildEntities);
        }
Alferd Nobel
  • 3,185
  • 2
  • 30
  • 35
0

If using HashMap, in newer versions of Java (8+) you can select each of 3 options:

public class UserProfileEntity {
    private String Code;
    private String mobileNumber;
    private LocalDateTime inputDT;
    // getters and setters here
}
HashMap<String, UserProfileEntity> upMap = new HashMap<>();


// remove by value
upMap.values().removeIf(value -> !value.getCode().contains("0005"));

// remove by key
upMap.keySet().removeIf(key -> key.contentEquals("testUser"));

// remove by entry / key + value
upMap.entrySet().removeIf(entry -> (entry.getKey().endsWith("admin") || entry.getValue().getInputDT().isBefore(LocalDateTime.now().minusMinutes(3)));
SM. Hosseini
  • 171
  • 1
  • 13
0

Iterators are not always helpful when another thread also modifies the collection. I had tried many ways but then realized traversing the collection manually is much safer (backward for removal):

for (i in myList.size-1 downTo 0) {
    myList.getOrNull(i)?.also {
       if (it == 5)
          myList.remove(it)
    }
}
Saeed Ir
  • 1,974
  • 2
  • 20
  • 22
-1

In case ArrayList:remove(int index)- if(index is last element's position) it avoids without System.arraycopy() and takes not time for this.

arraycopy time increases if(index decreases), by the way elements of list also decreases!

the best effective remove way is- removing its elements in descending order: while(list.size()>0)list.remove(list.size()-1);//takes O(1) while(list.size()>0)list.remove(0);//takes O(factorial(n))

//region prepare data
ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
Random rdm = new Random();
long millis;
for (int i = 0; i < 100000; i++) {
    Integer integer = rdm.nextInt();
    ints.add(integer);
}
ArrayList<Integer> intsForIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsDescIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsIterator = new ArrayList<Integer>(ints);
//endregion

// region for index
millis = System.currentTimeMillis();
for (int i = 0; i < intsForIndex.size(); i++) 
   if (intsForIndex.get(i) % 2 == 0) intsForIndex.remove(i--);
System.out.println(System.currentTimeMillis() - millis);
// endregion

// region for index desc
millis = System.currentTimeMillis();
for (int i = intsDescIndex.size() - 1; i >= 0; i--) 
   if (intsDescIndex.get(i) % 2 == 0) intsDescIndex.remove(i);
System.out.println(System.currentTimeMillis() - millis);
//endregion

// region iterator
millis = System.currentTimeMillis();
for (Iterator<Integer> iterator = intsIterator.iterator(); iterator.hasNext(); )
    if (iterator.next() % 2 == 0) iterator.remove();
System.out.println(System.currentTimeMillis() - millis);
//endregion
  • for index loop: 1090 msec
  • for desc index: 519 msec---the best
  • for iterator: 1043 msec
Nurlan
  • 720
  • 7
  • 12
-2

you can also use Recursion

Recursion in java is a process in which a method calls itself continuously. A method in java that calls itself is called recursive method.

Firas Chebbah
  • 415
  • 2
  • 12
  • 24
-3

this might not be the best way, but for most of the small cases this should acceptable:

"create a second empty-array and add only the ones you want to keep"

I don't remeber where I read this from... for justiness I will make this wiki in hope someone finds it or just to don't earn rep I don't deserve.

ajax333221
  • 11,436
  • 16
  • 61
  • 95