Let me give you some examples with some alternatives to avoid ConcurrentModificationException .
Suppose we have the following book collection
List<Book> books = new ArrayList<Book>(); books.add(new Book(new ISBN("0-201-63361-2"))); books.add(new Book(new ISBN("0-201-63361-3"))); books.add(new Book(new ISBN("0-201-63361-4")));
Collection and disposal
Collect all the records that you want to delete in the extended loop, and after the iteration is completed, you will delete all the records found.
ISBN isbn = new ISBN("0-201-63361-2"); List<Book> found = new ArrayList<Book>(); for(Book book : books){ if(book.getIsbn().equals(isbn)){ found.add(book); } } books.removeAll(found);
Suppose the operation you want to do is delete.
If you want to “add”, this approach will also work, but I would suggest that you iterate over another collection to determine which items you want to add to the second collection, and then issue the addAll method at the end.
Using ListIterator
Or you can use ListIterator , which supports the remove / add method during the iteration itself.
ListIterator<Book> iter = books.listIterator(); while(iter.hasNext()){ if(iter.next().getIsbn().equals(isbn)){ iter.remove(); } }
Again, I used the "remove" method, which seems to imply your question, but you can also use its add method to add new elements during the iteration.
Use JDK 8 streams
Or using the JDK 8 threads, lambdas / closures:
ISBN other = new ISBN("0-201-63361-2"); List<Book> filtered = books.stream() .filter(b -> b.getIsbn().equals(other)) .collect(Collectors.toList());
In these last two cases, to filter the elements from the collection and reassign the original reference to the filtered collection (i.e. books = filtered ) or use the filtered collection in removeAll find the elements from the original collection (i.e. books.removeAll(filtered) ).
Use a count or a subset
There are other alternatives. If the list is sorted and you want to remove consecutive items, you can create a sublist and then clear it:
books.subList(0,5).clear();
Since the subselection is maintained by the original list, this will be an effective way to remove this subset of elements.
Something similar can be achieved using sorted sets using the NavigableSet.subSet method or any of the cutting methods suggested there.
Questions:
Which method you use may depend on what you are going to do.
- The collection and removal method works with any collection (Collection, List, Set, etc.).
- The ListIterator method works only with lists, provided that their implementation
ListIterator offers support for add and delete operations. - The
Iterator approach will generally work on any collection if you are only going to use the iterator removal method. - The ListIterator / Iterator approach has the obvious advantage of not copying anything.
- Examples of third-party and JDK-8 streams actually do not delete anything, but look for the necessary elements, then you can replace the original link with a new one, and let the old one be garbage collected.
- In the process of collecting and removing it, the disadvantage is that we must repeat the iteration twice. We iterate over the loop in search of the element, and as soon as we find it, we will ask to remove it from the original list, which would mean a second iterative work to search for this element.
- I think it's worth mentioning that the remove method of the
Iterator interface is marked as optional in Javadocs, which means that there may be implementations of Iterator that can throw an UnsupportedOperationException . Thus, I would say that this approach is less secure than the first.