This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 1 year ago.
This is a code snippet to move to next element in the linked list. On debugging, itrPlaylist.next() is triggering a ConcurrentModificationException. I read that the list should not be modified while I am iterating. So, in this case, where did I go wrong? How can it be resolved?
Thanks in Advance.
public boolean nexxt() {
if(this.itrPlaylist.hasNext())
{
if(!bForward)
{
bForward = true;
itrPlaylist.next();
}
System.out.println("Now playing : " + itrPlaylist.next());
return true;
}
else
{
System.out.println("Reached end of " + this.getPlaylistName() + " playlist !");
}
return false;
}
Where is itrPlaylist is defined? Somethng like
itrPlaylist = list.iterator();
Above assignment should have happened after all the inserts have been done to the list. Looks like you have created one instance variable for itrPlaylist. And I think you might be doing
list.add(value);
after itrPlaylist has been initialized.
In that case, code will throw the above mentioned exception. This happens when some other code outside of iterator modifies the list when iterator is already initialized.
Related
In the code below I have a try catch block that attempts to remove an element from a Vector, using Iterator. I've created my own class QueueExtendingVect that extends Vector and implements Iterator.
The variable qev1 is an instance of class QueueExtendingVect. I've already added a few elements to this Vector as well.
try
{
qev1.iterator().remove();
}
catch(UnsupportedOperationException e)
{
System.out.println("Calling Iterator.remove() and throwing exception.");
}
qev1.enqueue(ci);
qev2.enqueue(ci);
qcv1.enqueue(ci);
qcv2.enqueue(ci);
for (int i = 1; i < 5; i++)
{
if (i % 2 == 0)
{
qev1.enqueue(new CInteger(i+1));
qev2.enqueue(new CInteger(i+1));
qcv1.enqueue(new CInteger(i+1));
qcv2.enqueue(new CInteger(i+1));
}
else
{
qev1.enqueue(new Date(i*i));
qev2.enqueue(new Date(i*i));
qcv1.enqueue(new Date(i*i));
qcv2.enqueue(new Date(i*i));
}
}
In this code I add a few elements to the Vector qev1. The other variables are in other parts of the code.
However, when I run my program I get an IllegalStateException at runtime. I'm not sure what this means.
You haven't called next() on your Iterator, so it's not referring to the first item yet. You can't remove the item that isn't specified yet.
Call next() to advance to the first item first, then call remove().
#rgettman answer is correct but to give you imagination.
Our collection: |el1| |el2| |el3|
when you call iterator.next() it works this way:
|el1| iterator |el2| |el3|
so it jumps over the element and return reference to the element which was jumped (|el1|). So if we called iterator.remove() now, |el1| would be removed.
It's worth to add what #PedroBarros mentioned above - you can't call iterator.remove() two times without iterator.next() between them because IllegalStateException would be thrown.
Also when you create two iterators (iterator1, iterator2) then calling:
iterator1.next();
iterator1.remove();
iterator2.next();
will throw ConcurrentModificationException because iterator2 checks that collection was modified.
It will also call this exeption, If you add something to the list in iterator and then after it not calling it.next() again but removing the item
This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 5 years ago.
for (FPlayer p : fPlayer.getFaction().getOnline()) {
p.setFaction(null);
}
Basically, the getOnline method returns an array list of the current FPlayers that are online. When the FPlayer is removed from their faction, the faction is set to null (p.setFaction(null)).
I cannot think about how to change my code to stop it from throwing the ConcurrentModificationException. I have used an iterator but still, it.next().setFaction(null) still throws the same exception.
EDIT:
USING A LIST ITERATOR:
ListIterator<FPlayer> it = fPlayer.getFaction().getOnline().listIterator();
while (it.hasNext()) {
it.next().setFaction(null);
}
Caused by: java.util.ConcurrentModificationException
At the line
it.next().setFaction(null)
EDIT #2:
Set faction method:
public void setFaction(Faction faction) {
if (hasFaction()) {
this.faction.getOnline().remove(this);
}
this.faction = faction;
if (faction != null) {
this.faction.getOnline().add(this);
}
}
This is happening because while iterating you are removing the data from the list .
Couple of solutions .
If the list size is small convert it to array and then loop over
Use for loop for iteration .
for(int i=0;i<fPlayer.getFaction().getOnline().size();i++)
{
// Condition to check if true
if(true)
{
fPlayer.getFaction().getOnline().remove(i);
i--;
}
}
Yes, change your code so it doesn't change the collection inside the loop you are running. For example, create a copy of the collection before iterating.
for (Foo foo : new ArrayList(myFoos)) {
if (foo.isBar()) {
myFoos.remove(foo);
}
}
Iterating and changing the list without the new ArrayList() would have caused a ConcurrentModificationException
This question already has answers here:
ConcurrentModificationException when using iterator and iterator.remove()
(4 answers)
Closed 6 years ago.
I have created this simple worker thread to calculate palindromes by iterating through an ArrayList.
I get an Error when I execute line temp_str1 = it.next();.
The ArrayList buffer_List is not used by any other thread hence using synchronized block does not help. I have looked through previous questions and they did not help much. I would eager to find the solution to this problem.
Here is My code:
private void find_Palindromes(ArrayList<String> buffer_List){
Iterator<String> it = buffer_List.iterator();
String temp_str1, temp_str2;
while(it.hasNext()){
temp_str1 = it.next();
//System.out.println(temp_str1);
it.remove();
if(is_Palindrome(temp_str1)){
to_Shared_Queue(temp_str1);
palin_count++;
}
}
}
Edit Code : added to_Shared_Queue
private void to_Shared_Queue(String str){
synchronized(shared_queue){
Shared_queue.add(str);
}
}
It is because of you modifying iterator while looping over it . you can do it by remove it from your array buffer_List.
buffer_List.remove(temp_str1);
This question already has an answer here:
java.util.NoSuchElementException using iterator in java
(1 answer)
Closed 7 years ago.
This is my code:
Iterator<H> iter = ((Main) getOwner()).eH.iterator();
while (iter.hasNext()) {
if (iter.next().z.c > p_l) {
if (r) {
if (iter.next().R) {
if (iter.next().p <= 0.7 * s && iter.next().c_l >= p_l) {
if (s_h == null) {
s_h = iter.next();
} else {
if (iter.next().p <= s_h.price) {
s_h = iter.next();
}
}
}
}
}
}
}
but I am getting this error:
Error during model startup:
java.util.NoSuchElementException
java.util.NoSuchElementException
at java.util.ArrayList$Itr.next(ArrayList.java:839)
at d_w.P.I(P.java:681)
at d_w.P.checkIfI(P.java:649)
at d_w.Main.initModelStructure(Main.java:1072)
at d_w.Main.onStartup(Main.java:2775)
at d_w.Main.start(Main.java:2765)
at com.anylogic.engine.Engine.start(Unknown Source)
at com.anylogic.engine.ExperimentSimulation.r(Unknown Source)
at com.anylogic.engine.ExperimentSimulation.run(Unknown Source)
at d_w.Simulation.executeShapeControlAction(Simulation.java:111)
I really not sure why I am getting this error any suggestion is highly appreciated thanks in advance
Calling .next() will retrieve the next element and advances the iterator. You have multiple .next() calls without checking if there is a next element at all.
If you want to keep using the same element that the .next() initially returned, then, replace the first .next() with H next = iter.next(), then access the next variable.
Every time you call next() you don't get the same element, instead you traverse to the next element of the iterator. You should save this value to a variable and use it.
Note: Not a duplicate of this question: Why am I not getting a java.util.ConcurrentModificationException in this example?. The question is, why the exception is not being thrown.
If we use foreach on List<String> and try to remove any element from it then it throws java.util.ConcurrentModificationException but why following code is not throwing the same exception and also not processing 2nd object of User?
public class Common {
public static void main(String[] args) {
User user1 = new User();
user1.setFirstname("Vicky");
user1.setLastname("Thakor");
User user2 = new User();
user2.setFirstname("Chirag");
user2.setLastname("Thakor");
List<User> listUser = new ArrayList<User>();
listUser.add(user1);
listUser.add(user2);
int count = 0;
for (User user : listUser) {
System.out.println(count + ":" + user.getFirstname()+" "+ user.getLastname());
count++;
listUser.remove(user);
}
}
}
The output is:
0:Vicky Thakor
Although the question is not an exact duplicate, the linked question: Why am I not getting a java.util.ConcurrentModificationException in this example? contains the answer.
The check that verifies whether to throw the exception is made when the next() method of the iterator has called, but this happens only if hasNext() returns true. In your case, when the list has two elements and you remove the first one in the first iteration the condition:
public boolean hasNext() {
return cursor != size(); // 1 != 1 after first iteration
}
is accidentally false, because cursor is at 1 and that's what size() is, at the moment. So next() is not called, and the exception is not being thrown.
Add a third element:
listUser.add(user2);
and the exception will be thrown. However, you should not rely on that behavior, because, as the documentation explains, it is not guaranteed:
Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
As NESPowerGlove stated in the comment sections the interator returns a fail-fast iterator according to the java doc, but it includes this
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: the fail-fast behavior of
iterators should be used only to detect bugs.
(Emphasis mine)
So, there is no guarantee that the exception will be thrown in the case of a modification.
Your loop could be rewritten as
Iterator<User> iterator = listUser.iterator();
while (iterator.hasNext()) {
User user = iterator.next();
System.out.println(count + ":" + user.getFirstname() + " " + user.getLastname());
listUser.remove(user);
}
and if we unroll the loop, it will look like
Iterator<User> iterator = listUser.iterator();
System.out.println(iterator.hasNext()); // prints true, loop executes
User user = iterator.next();
System.out.println(count + ":" + user.getFirstname() + " " + user.getLastname());
listUser.remove(user);
System.out.println(iterator.hasNext()); // prints false, loop stops
Until the second iterator.hasNext() call, collection is not modified, so all works as expected. Now the question is why the second iterator.hasNext() call returns false instead of throwing ConcurrentModificationException? Let's check ArrayList sources. I'll quote JDK 8 sources.
ArrayList.java, ArrayList's iterator declared at line 840 in class Itr. And it's hasNext() method is quite simple:
int cursor; // index of next element to return
...
public boolean hasNext() {
return cursor != size;
}
cursor is the index of the next element to return, size belongs to the outer ArrayList instance.
Checking for comodification implemented in the next() method.
Please note that you must not rely on this check in your own code. It designed to fight bugs, not provide you logic to rely upon. And it's not guaranteed to catch all your bugs (as demonstrated in your question). Probably performance is the reason why this check isn't implemented in hasNext() method.
Try this:
int count = 0;
for (User user : listUser) {
listUser.remove(user);
System.out.println(count + ":" + user.getFirstname()+" "+ user.getLastname());
count++;
}
for (User user : listUser) {
listUser.remove(user);
System.out.println(count + ":" + user.getFirstname()+" "+ user.getLastname());
count++;
}
I created the User class in less than 10 seconds. Contains two strings. But for the question, the User class is irrelevant. Assume Object and the problem remains. The key is to run this on debug and see what happens.
You will see the ConcurrentModificationException if you add the same for-each loop and try to iterate over the same list. The second time around, it would display:
0:Vicky Thakor
1:Chirag Thakor
Then throw the exception. Many people fail to remember that ConcurrentModificationException is a RuntimeException, and therefore, not documented on the API on the remove() method. The issue here is that you should trust the documentation. The documented safe way to remove an element while iterating is using the Iterator.