Scenario 1:::
So I have list of params, which is passed to 2 methods which calls web service and gets the data. These to methods just do stream.filter.collect on the list of params to get the needed parameter for rest call.
Now I have made the 2 calls parallel using CompletableFutures.
Can this throw ConcurrentModifcation exception?
Scenario 2:::
Similar setup as above , just that now one method changes the list of params and adds some objects to it. I know this is throwing Concurrent Modification exp. Should I just make list as copyonWriteArraylist or create new list with deep copy to avoid any further problems.
Scenario #1: Probably not, but your description is too vague to be sure.
Scenario #2: Most absolutely.
The only thing you need for CoModEx to occur is that the list is changed in any way. Be it add, addAll, clear, remove, retainAll, or any other method on List that has the effect of changing the list itself. Even fetching a sublist and changing THAT (as changes to sublist are visible from the 'outer' list that the sublist was created from).
CoModEx, despite the use of the word 'concurrent', has zip squat to do with threads. In fact, messing with a list from two threads simultaneously is one of the few ways you can break things (methods no longer do what their javadoc says they should) without causing a ConcurrentModificationException (will depend on how the race condition goes).
Here is a trivial way to get a CoModEx:
var list = new ArrayList<String>();
list.add("Hello");
list.add("World");
for (String item : list) if (item.equals("Hello")) list.remove(item);
That will throw it. Every time. CoModEx is thrown by iterators (and the for (x:y) constructor will implicitly create iterators, as does x.stream()..., which creates a spliterator, which also does this) when the underlying data structure was changed in any way that is not directly done by the (spl)iterator itself. For example, this is the one way you get to remove things from your own list using an iterator that does not result in CoModEx:
var it = list.iterator();
while (it.hasNext()) {
if (it.next().startsWith("Hello")) it.remove();
}
Note I'm calling iterator's remove, not list's remove, which would have caused CoModEx: That would change the underlying list (and not via the iterator directly), therefore any operation on an iterator created before the modification will throw CoModEx.
So, this is the flow:
You create an iterator from list, by entering for (String item : list).
That iterator's hasNext() is invoked to check if the for loop should be entered. It returns true
That iterator's next() is invoked for the first loop; Hello is returned.
Due to the code inside the for loop, list.remove("Hello") is invoked. This 'invalidates' all iterators that were created by this list so far.
the for loop loops, and invokes hasNext() to check if it should loop again.
hasNext realizes that it is invalid, and throws CoModEx.
ArrayList does this by having a counter which is incremented every time anything changes, and all iterators remember the value of the counter when created, and check that the list's counter value is equal to their own. If not, they throw CoModEx. Other list impls can use different mechanisms if they desire. Some go out of their way to actually allow this (such as CopyOnWriteArrayList, which explicitly details how it DOES let you modify itself during iteration).
If multiple threads are involved, all bets are off - those counter writes are not synchronized and therefore may or may not be visible by the threads involved. Don't access the same list from different threads unless you really know what you are doing.
Related
I have a LinkedList. Suppose that I'm inserting an element at the end and I want to save the position where was it inserted, so that I can call a function on an element next to it, whatever manages to get into this collection later. Is it possible with Java iterators? Many thanks.
Just to recollect, I'm not interested in reverse iteration. The application will be multithreaded, hence the weird requirement.
You can call List#listIterator(int index) with index = size() -1 to get an iterator to the current last element of the list. See documentation: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html
However, you are going to be stuck from there.
Whether the List implementation you are using isn't thread-safe, which is the case for LinkedList, ArrayList and most others, and any attempt to use the iterator after the list has been structurally modified is going to result in a ConcurrentModificationException being thrown.
A list is structurally modified when its size changes, i.e. on additions and removals.
Or the List implementation you are using is thread-safe, in which case you have no guaranty that the iterator will have access to the elements added to the list after the creation of the iterator.
For example, it wouldn't be the case with CopyOnWriteArrayList, for which the iterator iterates through data as it was at creation (like a snapshot).
You must find an implementation of List that clearly describe this behavior and explicitly say it in its documentation. As far as I know, there doesn't exist any that allow it, at least in the standard library.
To remove element from ArrayList, we can use-
Iterator remove() is used while iteration.
For ArrrayList remove() no iteration required.
Syntax is different in those cases. So
Do both use same logic internally?
Is there any more difference than logic?
Which one is better?
Any detailed explanation/link is highly appreciated.
An iterator might throw ConcurrentModificationException if an element is removed from the underlying collection in another way than the iterator's own remove() method.
So if you need to remove elements while iterating over a collection, you're allowed to do that with Iterator.remove() but you can't do that with Collection.remove() without risking to get an exception.
remove is a method that should be implemented (if no, it should throw UnsupportedOperationException) by all objects that are Iterable (implement interface Itarable). The way it works depends always on the object that implements it.
That means an ArrayList can implement it in a totally different way then i.e. LinkedList.
Removing object in Iterator requires You to iterate (find) the object You want to remove.
Using a remove method in ArrayList (there is no delete I can see in Javadoc: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html) finds the object for You and deletes it. It actually shifts objects in an underlying arrays to fill the "gap" You created by removing the object, so if You want to remove items in a list often, You could use LinkedList Instead.
Additionally while You are iterating through a list, You will cause an exception if You want to modify the collection in some other way than via iterator methods.
The exact answers to Your questions are:
1.No they use diferent logic, and additionally Iterator might even not allow to delete object (UnsupportedOperationException)
2.You cannot remove object by ArrayList remove while You are itereating, and to remove object at position 4 in ArrayList by using Iterator You would have to iterate 4 times "manually".
3.It depends whether You allready know what object do You want to remove, or first You check all the objects and decide whether to delete, during the iteration process. Additionally - If You want to delete objects often, You better use LinkedList, instead of ArrayList.
I have a for loop like
for (int neighbour : neighbours) {
Where I may modify neighbours within the loop. Found that thats the cause of ConcurrentModificationException. And read from https://stackoverflow.com/a/8189527/292291
Hence if you want to modify the list (or any collection in general),
use iterator, because then it is aware of the modifications and hence
those will be handled properly.
So I tried:
neighboursItr = neighbours.iterator();
while (neighboursItr.hasNext()) {
// try disconnecting vertices
neighbour = neighboursItr.next();
But that doesnt fix the problem. Why?
Are you calling neightbours.remove(neighbour)? In that case, that is the problem. You need to call neightboursItr.remove() instead.
Have you considered creating a new HashSet with desired state? I mean you can iterate through the neighbours and add to the newNeighbours whatever you want.
You may only modify the collection using methods of the iterator while iterating on the collection. So you may call neighboursItr.remove(), but you may not add an element to the collection using neighbours.add(), for example.
You cannot modify collection while iterating. The only exception is using iterator.remove() method (if it is supported by target collection).
The reason is that this is how iterator works. It has to know how to jump to the next element of the collection. If collection is being changed after iterator creation it cannot do this and throws exception.
There are several solutions for this problem. For example if you want to add elements to existing collection during iteration you can create yet another collection where you store new elements and then add all these elements after your iteration is finished.
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
What are the Advantages of Enhanced for loop and Iterator in Java ?
Is there a performance difference between a for loop and a for-each loop?
Below code shows that with both for loop as well as with iterator we can iterate the elements of collection then what is the difference between for loop and iterator and why we should use only iterator in case of collection
ArrayList<String> list=new ArrayList<String>();
list.add("dipu");
list.add("alok");
list.add("alok");
list.add("jyoti");
ArrayList<Integer> al=new ArrayList<Integer>();
al.add(1);
al.add(2);
String a[]={"a","b"};
for(int i=0;i<list.size();i++)
{
System.out.println(list.get(i));;
}
for(Integer t:al)
{
System.out.println(t);
}
for (Iterator iter = list.iterator(); iter.hasNext();)
{
System.out.println(iter.next());
}
Iterator it=list.iterator();
while(it.hasNext())
{
String st=it.next().toString();
System.out.println(st);
}
Though I'm not familiar with the Java Iterator, it seems very similar to .NET's IEnumerable.
The advantages of the enumerator/iterator are:
You don't have to know the size of the collection, which in some cases can require N steps to determine, increasing execution time (though it remains technically linear). Instead, you just keep moving to the next element until there aren't any.
Because the cardinality of the collection doesn't have to be known, iterators can allow collections to be generated dynamically, or "streamed" with elements being added while you begin work on what you already have. For instance, you could derive from Iterator and/or overload iterator getters to create classes that generate finite or infinite series "lazily", figuring out what each element in your enumerable collection is when you ask for it instead of when you define the collection. You could also set up a buffered stream, where you process records, packets, etc that you have received, while another thread or process works ahead of you to queue up more for you to work on.
Any collection that can provide an iterator can be traversed in exactly the same way, instead of having to know whether it's indexable, what the method or member is that defines size, etc etc etc. Iterator implementations thus provide an adapter to allow the same code to work on any collection passed to it.
Does Java have an equivalent to .NET extension methods (static methods that are not part of the class definition, but that work on instances of the type and can be called as if they were instance methods)? If so, you can define methods that take an Iterator and produce a result, which could be another Iterator. .NET's Linq library is based heavily on these, providing a very powerful collection-manipulation framework allowing for common operations to be chained together, each operating on the result of the previous operation.
Iterators are just generally safer I would say, no risk of accessing an index that isn't there. They also have a little more flexibility since you can go backwards and forwards with them whereas for loops only go one way and in many languages you cannot alter the value of the loop index within the loop (i.e. you cannot change the increment rate).
They are also the ONLY way to remove items from a collection while iterating through them. Removing an item from a collection while you were in a for loop through it would be disastrous and is generally not even allowed by Java, I forget what the exception is, but I've got one for doing that before.
Think about it, once you remove the item all the other ones shift down. Meanwhile on your next iteration your index was still incremented meaning 2 things.
First is that you will skip whatever the next element is as it was shifted to the position you just deleted from.
Second is that your loop will extend beyond the size of the collection which you have now altered.
I try to explain it with two short sentences:
With the enhanced for loop its easier to loop over it (more human readable..)
With the iterators it is possible to modify the list during the iteration, which is with the other methods not possible
The 'stream' you're iterating on might not even be indexable. That is, the iterator makes possible a very convenient 'lazy-evaluation' pattern where data isn't even loaded/constructed until the iterator asks for it. This is wonderful for repositories and database access, as well as networking.
I have a list of ListIterator<PointF> as a class field. I fill it in method grow(). When i try to use iterators from this list i get ConcurrentModificationException.
ListIterator<ListIterator<PointF>> i = mPoints.listIterator();
while (i.hasNext()) {
ListIterator<PointF> j = i.next();
if (j.hasNext())
PointF tmp = j.next(); // Exception here
}
I have no idea why does this code causes exeption in any method besides grow()
If the underlying list changes, the iterator that was obtained before that throws ConcurrentModificationException. So don't store iterators in instance fields.
What we can say for sure is that a ConcurrentModificationException means that the underlying iterable has been modified at some point after your call to get the iterator.
This does not always mean concurrent as in multi-threaded; one can easily trigger this exception by iterating through a list and deleting elements during the loop. So, if there are no other threads potentially modifying this, then we can say that the current thread has modified an iterator's underlying data structure at some point.
There's not enough code here to be sure, but your practice of storing iterators is a little suspicious. When did you add the (inner) iterators to mPoints? If the collection they refer to changes at any time after the iterator was created, it will throw this exception when invoked. Hence as soon as you add an iterator to the mPoints collection, the iterator's data structure is effectively locked for changes, and yet this won't be very clear in the code at all.
So I suspect this is the root cause of your problem. Unless it's for a very short term (and usually within a single lexical scope, e.g. a single method invocation) it's probably a bad idea to store iterators for the reason you're seeing. It might be better to store a reference to the underlying collections themselves, and then create the iterators during the code block above, something like:
ListIterator<Iterable<PointF>> i = mPoints.listIterator();
while (i.hasNext()) {
Iterator<PointF> j = i.next().iterator();
if (j.hasNext())
PointF tmp = j.next();
}
Then again the exact solution depends on the general architecture of your method. The main thing to bear in mind is don't store iterators long-term, because it's almost impossible to make this work reliably. Even if it does work right now, it creates a kind of invisible dependency between different parts of your code that will almost invariably be broken by someone implementing what should be a trivial change.