[ACCEPTED]-remove elements from CopyOnWriteArrayList-copy-on-write

Accepted answer
Score: 22

Iterate over the collection choosing all 7 the elements you want to delete and putting 6 those in a temporary collection. After you 5 finish iteration remove all found elements 4 from the original collection using method 3 removeAll.

Would that work out for you? I 2 mean, not sure if deletion logic is more 1 complicated than that in your algorithm.

Score: 7

EDIT: I'm an idiot. I missed the fact that this 18 is a copy-on-write list so every removal means a new copy. So my suggestions 17 below are likely to be suboptimal if there's 16 more than one removal.

Same as for any other 15 list whose iterator doesn't support remove, or 14 anything where you're not using an iterator. There 13 are three basic techniques that come to 12 mind to avoid this bug:

  1. Decrement the index 11 after removing something (being careful 10 not to do anything with the index until 9 the next iteration). For this you'll obviously 8 have to use a for(int i=0; i < ... style of for loop, so 7 that you can manipulate the index.

  2. Somehow 6 repeat what the inside of the loop is doing, without 5 literally going back to the top of the loop. Bit 4 of a hack - I would avoid this technique.

  3. Iterate 3 over the list in reverse (from end to start, instead 2 of from start to end). I prefer this approach 1 as it's the simplest.

Score: 6

Since this is a CopyOnWriteArrayList it is totally safe to remove 4 elements while iterating with forEach. No need 3 for fancy algorithms.

list.forEach(e -> {
    if (shouldRemove(e))
        list.remove(e);
});

EDIT: Well of course that 2 works if you want to delete elements by 1 reference, not by position.

Score: 2

Ususlly you would iterate first gathering 4 elemenet to be deleted in a separate list 3 then delete them outside the for each loop 2 (which is disguised iterator based loop 1 anyway)

Score: 1

Something like this:

int pos = 0;
while(pos < lst.size() ) {
  Foo foo = lst.get(pos);
  if( hasToBeRemoved(foo) ) {
    lst.remove(pos);
    // do not move position
  } else {
    pos++;
  }
}

0

Score: 1

You could use Queue instead of List.

private Queue<Something> queue = new ConcurrentLinkedQueue<Something>();

It's thread 3 safe and supports iterator.remove(). Be aware of the thread-safe 2 behavior of Queue iterators, though (check 1 the javadoc).

Score: 1

If you want to delete all use just clear(). If 3 you want to keep elements put them in a 2 temporary ArrayList and get them back from 1 there.

List<Object> tKeepThese= new ArrayList<>();
for(ListIterator<Object> tIter = theCopyOnWriteArrayList; tIter.hasNext();)
{
    tObject = tIter.next();
    if(condition to keep element)
        tKeepThese.add(tObject);
}
theCopyOnWriteArrayList.clear();
theCopyOnWriteArrayList.addAll(tKeepThese);
Score: 0

the shortest and most efficient way:

List<String> list = new CopyOnWriteArrayList<>();
list.removeIf(s -> s.length() < 1);

internally 8 it creates an temporary array with the same 7 length and copies all elements where the 6 predicate returns true.

keep in mind that 5 if you use this method to actually iterate 4 over the elements to perform some action, these 3 actions cannot be performed in paralell 2 anymore since the removeIf-call is atomic 1 and will lock the traversal for other threads

Score: 0

Below works fine with CopyOnWriteArrayList

for(String key : list) {
    if (<some condition>) {
        list.remove(key);
    }
}

0

More Related questions