Java LinkedList safest way to delete while iterating - java

I remember from a while back (I think it was some Java book) that the safest way to delete an element while iterating through a collection is using iterator.remove.
while(iterator.hasNext())
{
if(it.next().condition())
iterator.remove();
}
As I cannot find that reference and need a relative quick confirmation, can some java veteran confirm this?

This is the only legal way to structurally modify a LinkedList during iteration.
Any other way of removing an element from a linked list during iteration will (if you're lucky) throw a ConcurrentModificationException.
From the 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.

Related

How to prevent an ArrayList to be Structually Modified?

I am mapping a Table... say Employee to an ArrayList<Employee> which is a class level variable and I will be using it in multiple places instead of hitting the Data Base each time.
I want to keep it as read only, ie. no one can add or remove an element from the ArrayList once populated.
Can someone suggest a way to achieve this?
Edit: On modification I want some kind of Exception to be thrown.
Thanks in advance
You can use Collections.unmodifiableList. It will pass through reads to the backing list, so any updates to the backing (original) list will affect the immutable view that other classes see.
If you want an unmodifiable list that is not updated when the master list is updated, you'll need to call a copy constructor:
Collections.unmodifiableList(new ArrayList<Employee>(masterList));
Guava's immutable list is also an option in this case.
unmodifiable list is what you want here is the doc,and guava has an immutable list
You can provide a getter which will return a copy of the existing list.
Use a copy constructor for that:
class Employee {
private String id;
...
public Employee(Employee other) {
this.id = other.id;
...
}
}
List<Employee> getEmployeeData()
{
//create a new list using the existing one via copy constructor
return "Newly constructed list";
}
Other approach which comes to my mind is to get a private Iterator on the List after populating it, so 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. But note that the fail-fast behavior of an iterator cannot be guaranteed.
From javaDoc:
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.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness

Does Java Iterator do a second traversal to remove?

If I use a linked list Iterator to find an element, does calling remove() cause the Iterator to traverse the list again? The code is below
//The list is LinkedList<String> list; and has already been populated
Iterator itar = list.iterator();
while(itar.hasNext())
{
if(itar.next().equalsIgnoreCase("Foo"))
itar.remove();
}
A LinkedList in Java is a doubly linked list, meaning each node has a reference to the next and previous in the list.
When the iterator does a remove, it has a reference to the current node and simply reassigns the references in the next and previous (updating the head and tail references for the list itself if needed).
So, no; there is no additional iteration performed.
Also worth noting is that Java is open source these days. You can view the source for LinkedList here with the code the iterator's remove() calls here
Edit to Add: As noted in the comments, an iterator for a singly-linked list implementation could easily keep track of the previous node it iterated over and perform the same operation.
No, iterators always only iterate once even if you call remove().
Removing an item from a linked list updates the relevant pointers without requiring any further iterations.
No Iterator does not start from beginning but it will point to the next element if exist.I want to make you aware about one important thing of Iterator that they are "Fail Fast" means if a collection is modified by one of its methods after an iterator is created for that collection, the iterator immediately becomes invalid and operations performed with the iterator after this point throw ConcurrentModificationExceptions.

ConcurrentModificationException when removing an object from ArrayList [duplicate]

This question already has answers here:
Getting a ConcurrentModificationException thrown when removing an element from a java.util.List during list iteration? [duplicate]
(11 answers)
Closed 9 years ago.
my classes:
class Game{
ArrayList<Block> blocks;
public ArrayList<Block> getBlocks(){return blocks;};
}
class Block{
if(conditon) {
game.getBlocks().remove(this);
}
}
I have these classes, the ArrayList contains over 10 Block instances, if the condition for remove the current block in the Block class is true, i need remove this block from the ArrayList, but i got the Exception..
While iterating the Arraylist, you are not allowed to remove any item. If you want to remove an item while iteration, you can add removed item into newly created ArrayList say,.
willBeRemovedList after iteration completed you can remove all of them at a time.
ConcurrentModificationException is thrown by iterator because you modified a list and he can't get nextElement because he doesn't know what really happened to list he is iterating over.
for (Block block : blocks) {
blocks.remove(block);
}
This will throw exception when for loop tries to get next element of modified list, since Iterator is instantiated in the beginning of looping through list, iterator will be unable to choose right next element and will throw exception.
You can however remove current element from list you are iterating, but it should be done though Iterator itself. You would do something like this:
for (Iterator<Block> iterator = blocks.iterator(); iterator.hasNext(); iterator.next()){
iterator.remove();
}
The documentation of ArrayList class cleanly tells us the reason and how to avoid it:
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.
If a fail-fast iterator detects
that a modification has been made during iteration, it throws
ConcurrentModificationException, which is an unchecked exception. It is highly probable that you are iterating and modifying your collection in the same loop.
Also, the collections classes in the java.util package all return fail-fast iterators,
which means that they assume a collection will not change its contents during
the time a thread is iterating through its contents.

synchronization issue on LinkedHashMap

I am confused by one specific point regarding synchronization feature of LinkedHashMap. Here are the related Javadoc where I am confused. My confusion point is, why remove method is special here, which is mentioned by -- "except through the iterator's own remove method"?
http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
The iterators returned by the iterator method of the collections returned by all of this class's collection view methods are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, 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.
thanks in advance,
Lin
Basically, you're not allowed to structurally modify a map while iterating over it, since doing so would invalidate the iterator.
Iterator.remove() is specifically exempt from this, to enable you to easily write code like this:
Iterator<E> it = coll.iterator();
while (it.hasNext()) {
E val = it.next();
if (some_condition) {
it.remove();
}
}
It isn't special, it's the normal way of removing some item from a collection when using an iterator. If an element is removed "outside" the iterator, the iterator view of the given collection becomes inconsistent as compared to the actual collection since the iterator has no way of knowing why or how the element was removed.
Iterators can be of different types. There are iterators which "operate" on a given state of the collection in which case modifying the collection outside the iterator makes no difference. This is common for immutable collections. The other type of iterator is a "fail-fast" one which throws up an exception as soon as it finds out that the iterator is now looking at an old state of the collection (i.e. the collection was modified from outside). As mentioned in the docs, LinkedHashMap uses a fail-fast iterator.
It's not special, it acquires a sort of lock on the LinkedHashMap so that you are able to remove elements just through its remove method.
This because, as specified before:
A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order.
This means that you have a pending iterator on the data structure, allowing any modification would generate problems with respect to deterministic behavior (since the iterator would become inconsistent, as the underlying structure changed). So the implementation just make any structural modification fail with an exception as soon as you invoke any method if you have an open iterator on it.

How does an Iterator throw ConcurrentModificationException on add

How does Iterator throw ConcurrentModificationException when we are adding some object after current node or removing some object after current node. Does Iterator maintain a copy or reference to the underlying collection?
The iterator maintains a reference to the underlying collection. If you add or remove an element, the iterator might be left at an impossible index, or the collection might change "out from underneath" the iterator.
Therefore, instead of letting the iterator get corrupted without letting you know, most collections do the courtesy of throwing a ConcurrentModificationException when you try to modify the collection while iterating, so you don't wind up with unpredictably corrupted iterators.
By contract, you are not allowed to modify the collection while iterating over it (except by using Iterator.remove() et al).
Instead of randomly failing when you do this, the collection is nice enough to keep track of how many times it's been modified, and throw ConcurrentModificationException when it detects concurrent modification.
That ConcurrentModificationException is probably your friend and you ought to learn to live with it. However, just for completeness:
There are non-Oracle collections out there that don't throw ConcurrentModificationException. They're faster (because they don't spend time checking) and, obviously, more flexible, but they require greater care when using.
Oracle has four (at last count) "Concurrent" classes that don't throw it either in java.util.concurrent (ConcurrentHashMap, ConcurrentLinkedQueue, ConcurrentSkipListMap, and ConcurrentSkipListSet). They're marginally slower than their non-concurrent equivalents, but they're thread-safe and they dont block. They won't scramble your data no matter what you do, but they won't stop you from scrambling it.
For removing you can use iterator.remove(), as follows:
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object object = iterator.next();
/* ... */
if (condition) {
iterator.remove();
}
For adding you can replace simple Iterator for ListIterator, as follows
ListIterator<Object> iterator = list.listIterator();
iterator.add(new Object());
Of course an iterator has a link to the underlying collection, this avoids the copy. If you look for example at the source code of ArrayList iterator (ListItr), you'll see it mostly has a link to the list and a cursor.
So, don't share an iterator between threads and don't modify a collection on which you're iterating.

Categories

Resources