I have defined a ConcurrentLinkedQueue and looping over it like :
ConcurrentLinkedQueue clq
.forEach((carTask -> {
Now if I delete carTask from the queue. which is an element
in the queue while we are doing a forEach will that lead to any issue ?
One alternative I think of is put the elements to be deleted
in a separate List and once the forEach is over simply delete all
the elements in the Queue from the List.
I am not sure if this alternative approach will work perfectly
Any suggestions or better way to approach this problem ?
This specific example won't result in an error, because this implementation of Queue allows concurrent modifications.
But removing elements from Java collections via the remove method, while you're looping over the elements, will often result in a ConcurrentModificationException. Instead, it's a good habit to use an Iterator and call its remove method:
Collection<String> c = new LinkedList<>();
c.add("foo");
c.add("bar");
for(Iterator<String> it = c.iterator(); it.hasNext(); ) {
String s = it.next();
if(s.equals("foo")) {
it.remove();
}
}
// collection now contains only "bar"
In addition to preventing ConcurrentModificationException, this is preferable because the time complexity of remove for many collections is linear. Since this queue is implemeneted as a linked list, the list must be traversed until the element to be removed is located. With an Iterator, you've already located the element, and can remove it "in place".
What if you locate the element you want to remove, and it's the last element in the queue? Calling remove on that item requires a traversal all the way to the end of the queue again. In addition, it requires a call to equals for every preceding element. You definitely don't want to put the items to be removed into a list, because you'd have the same negative performance characteristics (along with the allocation of another List).
Related
This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
In Java, is it legal to call remove on a collection when iterating through the collection using a foreach loop? For instance:
List<String> names = ....
for (String name : names) {
// Do something
names.remove(name).
}
As an addendum, is it legal to remove items that have not been iterated over yet? For instance,
//Assume that the names list as duplicate entries
List<String> names = ....
for (String name : names) {
// Do something
while (names.remove(name));
}
To safely remove from a collection while iterating over it you should use an Iterator.
For example:
List<String> names = ....
Iterator<String> i = names.iterator();
while (i.hasNext()) {
String s = i.next(); // must be called before you can call i.remove()
// Do something
i.remove();
}
From the Java 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. 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.
Perhaps what is unclear to many novices is the fact that iterating over a list using the for/foreach constructs implicitly creates an iterator which is necessarily inaccessible. This info can be found here
You don't want to do that. It can cause undefined behavior depending on the collection. You want to use an Iterator directly. Although the for each construct is syntactic sugar and is really using an iterator, it hides it from your code so you can't access it to call Iterator.remove.
The behavior of an iterator is
unspecified if the underlying
collection is modified while the
iteration is in progress in any way
other than by calling this method.
Instead write your code:
List<String> names = ....
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
// Do something
it.remove();
}
Note that the code calls Iterator.remove, not List.remove.
Addendum:
Even if you are removing an element that has not been iterated over yet, you still don't want to modify the collection and then use the Iterator. It might modify the collection in a way that is surprising and affects future operations on the Iterator.
for (String name : new ArrayList<String>(names)) {
// Do something
names.remove(nameToRemove);
}
You clone the list names and iterate through the clone while you remove from the original list. A bit cleaner than the top answer.
The java design of the "enhanced for loop" was to not expose the iterator to code, but the only way to safely remove an item is to access the iterator. So in this case you have to do it old school:
for(Iterator<String> i = names.iterator(); i.hasNext();) {
String name = i.next();
//Do Something
i.remove();
}
If in the real code the enhanced for loop is really worth it, then you could add the items to a temporary collection and call removeAll on the list after the loop.
EDIT (re addendum): No, changing the list in any way outside the iterator.remove() method while iterating will cause problems. The only way around this is to use a CopyOnWriteArrayList, but that is really intended for concurrency issues.
The cheapest (in terms of lines of code) way to remove duplicates is to dump the list into a LinkedHashSet (and then back into a List if you need). This preserves insertion order while removing duplicates.
I didn't know about iterators, however here's what I was doing until today to remove elements from a list inside a loop:
List<String> names = ....
for (i=names.size()-1;i>=0;i--) {
// Do something
names.remove(i);
}
This is always working, and could be used in other languages or structs not supporting iterators.
Yes you can use the for-each loop,
To do that you have to maintain a separate list to hold removing items and then remove that list from names list using removeAll() method,
List<String> names = ....
// introduce a separate list to hold removing items
List<String> toRemove= new ArrayList<String>();
for (String name : names) {
// Do something: perform conditional checks
toRemove.add(name);
}
names.removeAll(toRemove);
// now names list holds expected values
Make sure this is not code smell. Is it possible to reverse the logic and be 'inclusive' rather than 'exclusive'?
List<String> names = ....
List<String> reducedNames = ....
for (String name : names) {
// Do something
if (conditionToIncludeMet)
reducedNames.add(name);
}
return reducedNames;
The situation that led me to this page involved old code that looped through a List using indecies to remove elements from the List. I wanted to refactor it to use the foreach style.
It looped through an entire list of elements to verify which ones the user had permission to access, and removed the ones that didn't have permission from the list.
List<Service> services = ...
for (int i=0; i<services.size(); i++) {
if (!isServicePermitted(user, services.get(i)))
services.remove(i);
}
To reverse this and not use the remove:
List<Service> services = ...
List<Service> permittedServices = ...
for (Service service:services) {
if (isServicePermitted(user, service))
permittedServices.add(service);
}
return permittedServices;
When would "remove" be preferred? One consideration is if gien a large list or expensive "add", combined with only a few removed compared to the list size. It might be more efficient to only do a few removes rather than a great many adds. But in my case the situation did not merit such an optimization.
Those saying that you can't safely remove an item from a collection except through the Iterator aren't quite correct, you can do it safely using one of the concurrent collections such as ConcurrentHashMap.
Try this 2. and change the condition to "WINTER" and you will wonder:
public static void main(String[] args) {
Season.add("Frühling");
Season.add("Sommer");
Season.add("Herbst");
Season.add("WINTER");
for (String s : Season) {
if(!s.equals("Sommer")) {
System.out.println(s);
continue;
}
Season.remove("Frühling");
}
}
It's better to use an Iterator when you want to remove element from a list
because the source code of remove is
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null;
so ,if you remove an element from the list, the list will be restructure ,the other element's index will be changed, this can result something that you want to happened.
Use
.remove() of Interator or
Use
CopyOnWriteArrayList
I have a problem iterating my priority queue which cost Concurrentmodificationexception.
code for iterating:
Queue<Patient> pq = new PriorityQueue<Patient>();
Iterator<Patient> it = pq.iterator();
while(iter.hasNext()){
Patient current = iter.next();
if(current.getName().equals(patientName)){
pq.remove(p);
}
}
There error says that iter.next() cost Concurrentmodificationexception.
May i please know how to resolve this? i have search the internet but the still cant find a solution to this.
Change your code to following for solving it -
Queue<Patient> pq = new PriorityQueue<Patient>();
Iterator<Patient> iter = pq.iterator();
while(iter.hasNext()){
Patient current = iter.next();
if(current.getName().equals(patientName)){
iter.remove();
}
}
Explanation ConcurrentModificationException is thrown from next() method of iterator, if there is any structural change in the underlying collection (in your case Queue) i.e. any element is added or removed in the queue directly. It is called Fail Fast Iterator.
Try to use ConcurrentLinkedQueue instead of PriorityQueue
Acording to: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html
Beware that, unlike in most collections, the size method is NOT a constant-time operation. Because of the asynchronous nature of these queues, determining the current number of elements requires a traversal of the elements, and so may report inaccurate results if this collection is modified during traversal.
Since Java8, you can remove using removeIf which is part of Collection contract.
Given that removeIf method takes a predicate, your code could be as simple as :
priorityQueue.removeIf(patient -> patient.getName().equals(patientName));
As for the Concurrent exception you had, this simply happened because you tried to remove calling PriorityQueue#remove directly while you were already iterating which would make the iterator obsolete. The proper way to remove when iterating is by using Iterator#next and then Iterator#remove (this is actually what de default implementation of removeIf does).
I was asked in an interview what is the advantage of using iterator over for loop or what is the advantage of using for loop over iterator?
Can any body please answer this?
First of all, there are 2 kinds of for loops, which behave very differently. One uses indices:
for (int i = 0; i < list.size(); i++) {
Thing t = list.get(i);
...
}
This kind of loop isn't always possible. For example, Lists have indices, but Sets don't, because they're unordered collections.
The other one, the foreach loop uses an Iterator behind the scenes:
for (Thing thing : list) {
...
}
This works with every kind of Iterable collection (or array)
And finally, you can use an Iterator, which also works with any Iterable:
for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
Thing t = it.next();
...
}
So you in fact have 3 loops to compare.
You can compare them in different terms: performance, readability, error-proneness, capability.
An Iterator can do things that a foreach loop can't. For example, you can remove elements while you're iterating, if the iterator supports it:
for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
Thing t = it.next();
if (shouldBeDeleted(thing) {
it.remove();
}
}
Lists also offer iterators that can iterate in both directions. A foreach loop only iterates from the beginning to an end.
But an Iterator is more dangerous and less readable. When a foreach loop is all you need, it's the most readable solution. With an iterator, you could do the following, which would be a bug:
for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
System.out.println(it.next().getFoo());
System.out.println(it.next().getBar());
}
A foreach loop doesn't allow for such a bug to happen.
Using indices to access elements is slightly more efficient with collections backed by an array. But if you change your mind and use a LinkedList instead of an ArrayList, suddenly the performance will be awful, because each time you access list.get(i), the linked list will have to loop though all its elements until the ith one. An Iterator (and thus the foreach loop) doesn't have this problem. It always uses the best possible way to iterate through elements of the given collection, because the collection itself has its own Iterator implementation.
My general rule of thumb is: use the foreach loop, unless you really need capabilities of an Iterator. I would only use for loop with indices with arrays, when I need access to the index inside the loop.
Iterator Advantage:
Ability to remove elements from Collections.
Ability to move forward and backward using next() and previous().
Ability to check if there more elements or not by using hasNext().
Loop was designed only to iterate over a Collection, so if you want just to iterate over a Collection, its better to use loop such as for-Each, but if you want more that that you could use Iterator.
The main difference between Iterator and the classic for loop, apart from the obvious one of having or not having access to the index of the item you're iterating, is that using Iterator abstracts the client code from the underlying collection implementation, allow me to elaborate.
When your code uses an iterator, either in this form
for(Item element : myCollection) { ... }
this form
Iterator<Item> iterator = myCollection.iterator();
while(iterator.hasNext()) {
Item element = iterator.next();
...
}
or this form
for(Iterator iterator = myCollection.iterator(); iterator.hasNext(); ) {
Item element = iterator.next();
...
}
What your code is saying is "I don't care about the type of collection and its implementation, I just care that I can iterate through its elements". Which is usually the better approach, since it makes your code more decoupled.
On the other hand, if you're using the classic for loop, as in
for(int i = 0; i < myCollection.size(); i++) {
Item element = myCollection.get(i);
...
}
Your code is saying, I need to know the type of collection, because I need to iterate through its elements in a specific way, I'm also possibly going to check for nulls or compute some result based on the order of iteration. Which makes your code more fragile, because if at any point the type of collection you receive changes, it will impact the way your code works.
Summing it up, the difference is not so much about speed, or memory usage, is more about decoupling your code so that is more flexible to cope with change.
if you access to data by number (e.g. "i"), it is fast when you use array. because it goes to element directly
But, other data structure (e.g. tree, list), it needs more time, because it start from first element to target element. when you use list. It needs time O(n). so, it is to be slow.
if you use iterator, compiler knows that where you are. so It needs O(1)
(because, it start from current position)
finally, if you use only array or data structure that support direct access(e.g. arraylist at java). "a[i]" is good. but, when you use other data structure, iterator is more efficient
Unlike other answers, I want to point another things;
if you need to perform the iteration in more than one place in your code, you will likely end up duplicating the logic. This clearly isn’t a very extensible approach. Instead, what’s needed is a way to separate the logic for selecting the data from the code that actually processes it.
An iterator solves these problems by providing a generic interface for looping over a set of data so that the underlying data structure or storage mechanism — such as an array- is hidden.
Iterator is a concept not an implementation.
An iterator provides a number of operations for traversing and accessing data.
An iterator may wrap any datastructure like array.
One of the more interesting and useful advantages of using iterators is the capability to wrap or decorate another iterator to filter the return values
An iterator may be thread safe while a for loop alone cannot be as it is accessing elements directly. The only popular thread-safety iterator is CopyOnWriteArrayList but it is well known and used often so worth mentioning.
This is from the book that it is https://www.amazon.com/Beginning-Algorithms-Simon-Harris/dp/0764596748
I stumbled on this question. The answer lies to the problems Iterator tries to solve:
access and traverse the elements of an aggregate object without exposing its representation
define traversal operations for an aggregate object without changing its interface
I have a linkedlist where each element has key and value(ArrayList<dataStructure>). I want to merge the elements having same key.
Iterator<CElem> oItr = linkedList.iterator();
{
while (oItr.hasNext())
{
CElem outer = oItr.next();
Iterator<CElem> iItr = linkedList.iterator();
{
while (iItr.hasNext())
{
CElem inner = iItr.next();
if (outer.equals(inner))
continue;
if (outer.getKey().equals(inner.getKey()))
{
outer.getValues().addAll(inner.getValues());
iItr.remove();
}
}
}
}
}
Though I am using the iterators remove methog getting a java.util.ConcurrentModificationException. What should be changed to get rid of this.
You remove element with one of your iterators, thus the second of them does not know about this removal and ConcurrentModificationException is thrown
BTW:
you should consider using some multimap in place of list that is having key-values pairs
Add the elements you want to remove in another List and then loop in that list at the end to remove these elements.
Alternatively, use a Map/Set.
Both your iterators are traversing the linked list
Iterator<CElem> oItr = linkedList.iterator();
....
Iterator<CElem> iItr = linkedList.iterator();
probably iItr should be for the inner array list?
UPDATE Scratch above answer I misread the question. The challenge though is that you have two iterators traversing the list, so while you use one iterator's remove() method, the other still detects the concurrent modification.
Normally, to remove duplicates from a list, you can just run them through a Set (e.g. a HashSet) but that won't work for you as it's only key duplication, not the entire member of the list.
I'd take an approach where I try to find and capture the duplicated keys and their values in a separate list and then merge in and remove the duplicates as a separate step.
The problem is that when you use the iItr.remove() it modifies the list, which iItr is happy with because it knows what changed, but oItr isn't. There are three possible solutions to this that I can see:
Switch to a concurrent list (e.g. ConcurrentLinkedQueue - but see then answers at Lock-Free Concurrent Linked List in Java for warnings about this)
Switch to a set structure, e.g. TreeSet, which will keep your items unique automatically (but won't preserve their order)
Make sure you don't use the other iterator after removing from one of them -- you could do this by switching which element you are removing, i.e. change iItr.remove() to:
oItr.remove();
break;
This would cause the first instance of each key to be removed, rather than subsequent ones, which might not be the behaviour you want -- in that case you could try iterating over the lists backwards.
Will this work?
Iterator<CElem> oItr = linkedList.iterator();
{
while (oItr.hasNext())
{
CElem outer = oItr.next();
Iterator<CElem> iItr = linkedList.iterator();
{
while (iItr.hasNext())
{
CElem inner = iItr.next();
if (outer.equals(inner))
continue;
if (outer.getKey().equals(inner.getKey()))
{
inner.getValues().addAll(outer.getValues());
outer.remove();
break;
}
}
}
}
}
I am getting an exception when I try to remove elements from CopyOnWriteArrayList using an iterator.
I have noticed that it is documented
Element-changing operations on iterators themselves (remove, set, and add) are not supported. These methods throw UnsupportedOperationException.
(from http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html)
Now, surprisingly i can iterate it with foreach and use the remove() function . But then I get the famous bug - when trying to remove an item from a list using a for loop - you skip the element next to the removed element.
any suggestions then?
Iterate over the collection choosing all the elements you want to delete and putting those in a temporary collection. After you finish iteration remove all found elements from the original collection using method removeAll.
Would that work out for you? I mean, not sure if deletion logic is more complicated than that in your algorithm.
EDIT: I'm an idiot. I missed the fact that this is a copy-on-write list so every removal means a new copy. So my suggestions below are likely to be suboptimal if there's more than one removal.
Same as for any other list whose iterator doesn't support remove, or anything where you're not using an iterator. There are three basic techniques that come to mind to avoid this bug:
Decrement the index after removing something (being careful not to do anything with the index until the next iteration). For this you'll obviously have to use a for(int i=0; i < ... style of for loop, so that you can manipulate the index.
Somehow repeat what the inside of the loop is doing, without literally going back to the top of the loop. Bit of a hack - I would avoid this technique.
Iterate over the list in reverse (from end to start, instead of from start to end). I prefer this approach as it's the simplest.
Since this is a CopyOnWriteArrayList it is totally safe to remove elements while iterating with forEach. No need for fancy algorithms.
list.forEach(e -> {
if (shouldRemove(e))
list.remove(e);
});
EDIT: Well of course that works if you want to delete elements by reference, not by position.
Ususlly you would iterate first gathering elemenet to be deleted in a separate list then delete them outside the for each loop (which is disguised iterator based loop anyway)
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++;
}
}
You could use Queue instead of List.
private Queue<Something> queue = new ConcurrentLinkedQueue<Something>();
It's thread safe and supports iterator.remove(). Be aware of the thread-safe behavior of Queue iterators, though (check the javadoc).
If you want to delete all use just clear(). If you want to keep elements put them in a temporary ArrayList and get them back from 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);
the shortest and most efficient way:
List<String> list = new CopyOnWriteArrayList<>();
list.removeIf(s -> s.length() < 1);
internally it creates an temporary array with the same length and copies all elements where the predicate returns true.
keep in mind that if you use this method to actually iterate over the elements to perform some action, these actions cannot be performed in paralell anymore since the removeIf-call is atomic and will lock the traversal for other threads
Below works fine with CopyOnWriteArrayList
for(String key : list) {
if (<some condition>) {
list.remove(key);
}
}