I'm having the following issue:
Given:
public class A{
Collection<B> elements = new ArrayList<B>();
}
public class B{
Collection<B> linkedElements = new ArrayList<B>();
}
All the elements of linkedElements belongs to elements too.
I want that each time that an element is deleted from the elements collection, its linked elements gets deleted from that collection too.
I've tried attaching a observer to the Iterator.remove operation and fire there the removal of linkedElements from the elements list, but because of the logic itself, I always run into a ConcurrentModificationException.
Update:
This is the code that causes the error:
public class A{
Collection<B> elements = new ArrayList<B>(){
public Iterator<B> iterator() {
return new ProxyIterator(super.iterator());
};
private class ProxyIterator implements Iterator{
Iterator it;
Object lastObject;
public ProxyIterator(Iterator proxied){
it = proxied;
}
#Override
public boolean hasNext() {
return it.hasNext();
}
#Override
public Object next() {
return lastObject = it.next();
}
#Override
public void remove() {
it.remove()
for (B linkedElement : ((B)lastObject).getlinkedElements()) {
A.this.getElements().remove(linkedElement);
}
}
}
}
With this code, just calling a A.getElements().clear() will fire a ConcurrentModificationException... and its ok, because I'm removing all linked elements from from the elements list while removing one single element. That's why I need another approach.
It's because you're modifying the array while you're iterating over it. From the javadocs for ArrayList:
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.
So, once you do A.this.getElements().remove(linkedElement); in the remove method, you've now just structurally modified the list via a means other than the iterator it's "remove" method, which means the iterator will throw the CME.
Dealing with this will probably be tricky. I can think of a few options offhand, all of which have complications:
Switch to CopyOnWriteArrayList, since its iterators are fail-safe. Downside is that your iterator may potentially still show items that were removed previously. (On the other hand, you have to deal with that sort of risk anyway, since you could also have already iterated past a child of whatever you're removing.) If this works for you, this is almost certainly the easiest and most reliable option.
Following the for loop in remove, replace it with a new Iterator that you manually advance to the correct location. Hard to do if your list allows duplicate items.
Re-implement ArrayList.Iterator; in your remove method, you can track the changes you're making and update your iterator appropriately.
Finally, as a last question / warning - do you want this traversal to be recursive? Right now, if you had elements Foo linked to Bar, and Bar linked to Baz, removing Foo from the iterator would result in Bar being removed, but there's nothing that would then remove Baz. (Whereas if you removed Bar first, then Baz would be removed.) In general if you want to modify the removal behavior of a Collection, you'd be better off doing it List.remove rather than Iterator.remove.
Related
I have some questions about the different behaviors of Iterator on the main Java Framework Collection classes (not only for the List class).
List
If I write for-each I will have an exception:
Collection<String> cc= new ArrayList<>(3);
cc.add("Cio");
cc.add("Mio");
cc.add("Tio");
for (String s:cc) {
System.out.println(s);
cc.remove(s); //Exception
}
If I use the Iterator, I will have not an exception:
for (Iterator<String> it =cc.iterator(); it.hasNext();) {
String s =it.next();
if (s.startsWith("C"))
it.remove();
}
ArrayDeque
This is different for ArrayDeque, infact if I use for-each, I will
have not an exception:
ArrayDeque<String> greetings = new ArrayDeque<String>();
greetings.push("hello");
greetings.push("hi");
greetings.push("ola");
greetings.pop();
greetings.peek();
while (greetings.peek() != null)
System.out.print(greetings.pop());
But if I use the iterator, I will have an exception:
Iterator<String> it = greetings.iterator();
while(it.hasNext()) {
System.out.println(greetings.pop()); //Exception
}
Why? And does the iterator throw an exception for the other JFC collections, in particular: HashSet, TreeSet, LinkedList?
Thanks a lot!
A.
ArrayList
The list maintains a modCount field that is incremented each time a structural modification is done to the list.
Structural modifications are those that change the size of the list,
or otherwise perturb it in such a fashion that iterations in progress
may yield incorrect results.
Further...
If the value of this field changes unexpectedly, the iterator (or list
iterator) will throw a ConcurrentModificationException in response to
the next, remove, previous, set or add operations. This provides
fail-fast behavior, rather than non-deterministic behavior in the face
of concurrent modification during iteration.Use of this field by
subclasses is optional.
If a subclass wishes to provide fail-fast iterators (and list
iterators), then it merely has to increment this field in its add(int,
E) and remove(int) methods (and any other methods that it overrides
that result in a structural modification the list.
The two peice of list iteration code :
1.
for (String s:str1) {
System.out.println(s);
str1.remove(s);
}
and
2.
Iterator<String> i1 = str.iterator();
while(i1.hasNext()) {
i1.next();
i1.remove();
}
--may seem identically but are internally a bit different.
Its worth mentioning that the iterator of the list maitains a expectedModCount. That should be in sync with modCount when modifying the list while iterating.
In 1st case, String s:str1 gets the iterator, checks hasNext() and calls the next(), just like in the 2nd case. The difference comes in remove() method call. str1.remove(s); calls the remove method of the ArrayList. This increments the modCount but not expectedModCount. So in the second iteration, when next() is called it throws ConcurrentModificationException. On the other hand, in 2nd case, i1.remove(); calls the remove method from Iterator implementation in ArrayList. This increments the the modCount and expectedModCount and -- Bingo.
Note: Missing the i1.next(); in the second scenario will cause IllegalStateExcepton. This is because the cursor for the next element in the list is not updated.
TakeAway: Dont call the list.remove(element) method while iterating the list. This method is meant to be called when not in an iteration.
ArrayDeque
If you iterate the ArrayDeque like this:
Iterator<String> i1 = str.iterator();
while(i1.hasNext()) {
i1.next();
i1.remove();
}
-- it works the exact same way as its ArrayList counterpart.
When calling pop() or push() method of the ArrayDeque class, you don't actually iterate on the queue, you just modify the head or tail of the queue. This is just like calling remove() method of the ArrayList class when not in Iteration (not the remove() of Iterator of ArrayList). This doesn't qualify to be a structural modification. So it doesn't throw an Exception.
Refer this article.
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
I just have a general question about a program that I am doing.
I have a linked list and one of the instance variable is a version int to make sure there are no concurrent modification exceptions.
If I add an element to the linked list then I change the version.
I also use a custom iterator that iterates through the linked list that also has it's own version. When the linkedList iterator is created, it sets the iterator's version equal to the linkedList's version.
My question is:
If I remove an element with my Iterator should I change the iterators version as well?
Basically every method in the Iterator class it first checks to make sure the versions are the same, and if it's not it throws a new concurrent modification exception.
Does it matter if the iterator changes the list?
My question is: If I remove an element with my Iterator should I change the iterators version as well?
Yes, usually you should also change the version of your Iterator, as long as you want to allow modifications to the list by the Iterator. Otherwise you should throw a java.lang.UnsupportedOperationException.
Have a look at how the Iterator of java.util.LinkedList handles modifications: During the add and remove methods it first calls checkForComodification()
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
and at the end it will increase expectedModCount by one:
public void add(E e) {
checkForComodification();
[...]
expectedModCount++;
}
My question is about synchronizedList method Collections Class.
Javadocs say:
It is imperative that the user manually synchronize on the returned list when iterating over it:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Though manually synchroniziation is not required for other methods. I looked into the source code of Collections class
and found shyncronization has already been taken care for all methods like add
public boolean add(E e) {
synchronized(list) {return c.add(e);}
}
but not for iterator method. I think iterator method could have also handled synchronization in the same fashion
as above method (it would have avoided the extra work i.e manual synchronization for programmers). i am sure there
must be some concrete reason behind it but i am missing it?
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
A way to avoid manual synchronization from Programmer
public Iterator<E> iterator() {
synchronized(list) {
return c.iterator(); // No need to manually synched by user!
}
}
I think iterator method could have also handled synchronization in the same fashion as above method
No, it absolutely couldn't.
The iterator has no control over what your code does between calls to the individual methods on it. That's the point. Your iteration code will call hasNext() and next() repeatedly, and synchronization during those calls is feasible but irrelevant - what's important is that no other code tries to modify the list across the whole time you're iterating.
So imagine a timeline of:
t = 0: call iterator()
t = 1: call hasNext()
t = 2: call next()
// Do lots of work with the returned item
t = 10: call hasNext()
The iterator can't synchronize between the end of the call to next() at t=2 and the call to hasNext() at t=10. So if another thread tries to (say) add an item to the list at t=7, how is the iterator meant to stop it from doing so?
This is the overall problem with synchronized collections: each individual operation is synchronized, whereas typically you want a whole chunky operation to be synchronized.
If you don't synchronize the entire iteration, another thread could modify the collection as you iterate, leading to a ConccurentModificationException.
Also, the returned iterator is not thread-safe.
They could fix that by wrapping the iterator in a SynchronizedIterator that locks every method in the iterator, but that wouldn't help either – another thread could still modify the collection between two iterations, and break everything.
This is one of the reasons that the Collections.synchronized*() methods are completely useless.
For more information about proper thread-safe collection usage, see my blog.
If you want to avoid manual synchronization, you have to use a Collection like java.util.concurrent.CopyOnWriteArrayList. Every time an object is added to the list, the underlying datastructure is copyied to avaoid a concurrent modification exception.
The reason why you need manual serialization on the Iterator in your example is that the Iterator uses the same internal datastructure as the list but they are independend objects and both Iterator and list can be accessed by different threads at any arbitrary moment in time.
Another aproach would be to make a local copy of the list and iterate over the copy.
I have a List, and I want to loop through that List and remove some record base on some condition. Here is what I do
public void foo(List<Bar> recordList){
for(Bar bar : recordList){
if(bar.someCondition()){
recordList.remove(bar);
}
}
}
This code generate exception. If I use Iterator then it works fine
public void foo(List<Bar> recordList){
Iterator<Bar> iter = recordList.iterator();
while(iter.hasNext()){
Bar bar = iter.next();
if(bar.someCondition()){
iter.remove();
}
}
}
I guess my question:
Why the first piece of code does not work?
How do I make the first piece of code work?
The documentation is very clear on this.
http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html
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.
It doesn't work because you are modifying a collection WHILE iterating on it. It means you are changing its state and reading it at the same time. This provokes unexpected behaviours in the inners of the collection, and to prevent data corruption, an exception is thrown.
You don't make it work. You have to use iterators.