Removing an object is causing freezes - java

[For clarification, 'monsters' is a list of NPCs that when shot by an object 'bullet' are removed from the list. ]
Error at start:
W/System.err: java.util.ConcurrentModificationException
W/System.err: at java.util.ArrayList$Itr.next(ArrayList.java:831)
W/System.err: at com.companyname.product.GameplayScene.update(GameplayScene.java:113)
//...
I believe this means that it is trying to perform an action on something in the list that isn't there. So my question is could I please get some help identifying the point where an object is being called that isn't there, as I can't seem to find it. I know which class it is in as the first line references it for each error.
for (Bullet bullet : player.getList())
if (npcManager.bulletCollide(bullet)) { //checks for a collision between all npcs and all bullets
player.getList().remove(bullet);//npc is removed in method above
}
if (!gameOver) {
npcManager.update(); //updates movement of npcs
if (npcManager.playerCollideNPC(player)) {
//end game
}
}
for (RectNPC NPC : npcManager.getList())
if (obstacleManager.NPCCollide(NPC)) { //checks collision between npcs and other objects
//
}
int i = 0;
//checks collisions between NPCs themselves
while (i < (Constants.NUMBER_ENEMIES - 1)) {
if (npcManager.getList().size() <= 1)
return;
if (Rect.intersects(npcManager.getList().get(i).getRectangle(), npcManager.getList().get(i + 1).getRectangle()))
npcManager.getList().get(i).setRectangle(200);
i += 1;
}
}
(Above) I imagine the issue will be with calling something in the update (shown above) where the object is no longer available, is there an issue with any of how I am removing the NPCs?
public boolean bulletCollide(Bullet bullet) {
for(RectNPC npc : monsters) {
if(npc.bulletCollideNPC(bullet)) {
monsters.remove(npc);
monsters.add(0, new RectNPC(new Rect(100, 100, 200, 200), Color.rgb(255, 0, 0), 25));
return true;
}
}
return false;
}
(Above) Code where I am removing the NPC, I've included incase it is helpful - however it does do what it's meant to so I don't believe this is the problem.
My main question is, is there anything here that would be causing this error (the game stopping for a few frames and giving the error at the top) - or is there something/somewhere else in specific I should be looking at? Also I know some of my syntax isn't great, I apologise it's my first Java project.
Current Iterators:
for(Iterator<RectNPC> iterator = monsters.iterator(); iterator.hasNext();) {
if(iterator.next().bulletCollideNPC(bullet)) {
iterator.remove();
monsters.add(0, new RectNPC(new Rect(100, 100, 200, 200), Color.rgb(255, 0, 0), 25));
return true;
}
}
and
for (Iterator<Bullet> iterator = player.getList().iterator(); iterator.hasNext(); ) {
if (npcManager.bulletCollide(iterator.next())) {
iterator.remove();
//
}
}

In java, you cannot do for( T variable : collection ) { collection.remove( variable ); } In other words, you cannot be removing items from a collection which is being iterated with a for loop. It will result in a ConcurrentModificationException. Google for "java fail-fast iterator" for more information about why and how.
You have two options:
Collect in a temporary list all the monsters that are to be removed, then once you are done iterating over the main list, iterate once more through the temporary list to remove them from the main list. The point is that you are not going to be removing from the same list that you are iterating.
Instead of a "foreach" (for) loop, use an actual iterator, and when you want to remove an item, remove it by invoking the iterator's remove() method, not the containing collection's remove() method. The iterator's remove() method does the necessary tricks to prevent a ConcurrentModificationException from being thrown.

Use Iterator for a safe way to remove your Elements.
Note that Iterator.remove is the only safe way to modify a collection
during iteration; the behavior is unspecified if the underlying
collection is modified in any other way while the iteration is in
progress.
From Java SE documentation
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
Example

Your method is doing 3 different things. It's returning a boolean, removing an element from a list, and then adding an element. I would restructure the code so that you have 3 methods that do only 1 thing.
You can use the power of Java 8's internal iterator, as a starting point
monsters.removeIf(e -> e.bulletCollideNPC(bullet));

Related

Why the iterator throws a exception for Integer linkedlist [duplicate]

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

Iterator.remove() IllegalStateException

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

Remove element from ArrayList internally

I have the following code:
class Action {
public void step(Game game) {
//if some condition met,
// then remove self from action stack
game.actionStack.remove(this);
}
class Game (
public ArrayList<Action> actionStack;
public Game() {
actionStack = new Arraylist<Action>();
actionStack.add(new Action());
while (true) {
for (Action action : this.actionStack) {
action.step(this);
}
}
}
}
An exception gets thrown when game.actionStack.remove(this); occurs. Is there a way to remove the element safely from inside the Action class like I want?
I'm guessing you're getting a ConcurrentModificationException because you're calling the list remove method while iterating it. You can't do that.
An easy fix is to work on a copy of the array when iterating:
for (Action action : new ArrayList<>(this.actionStack)) {
action.step(this);
}
A slightly more efficient fix is to use an explicit Iterator and call its remove method. Perhaps have step() return a boolean indicating whether it wants to remain in the list for the next step or not:
for (Iterator<Action> it = this.actionStack.iterator(); it.hasNext();) {
Action action = it.next();
if (!action.step(this)) {
it.remove();
}
}
From : the java tutorial we get the following:
Iterators
...
Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Use Iterator instead of the for-each construct when you need to:
Remove the current element. The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.
Iterate over multiple collections in parallel.
The following method shows you how to use an Iterator to filter an arbitrary Collection — that is, traverse the collection removing specific elements.
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
This simple piece of code is polymorphic, which means that it works for any Collection regardless of implementation. This example demonstrates how easy it is to write a polymorphic algorithm using the Java Collections Framework.
Note: I assume, you implemented equals and hashCode methods for your class
You need to use iterator to remove like below;
class Game (
public ArrayList<Action> actionStack;
public Game() {
actionStack = new Arraylist<Action>();
actionStack.add(new Action());
while (true) {
for (Iterator<Action> it = this.actionStack.iterator(); it.hasNext(); ) {
it.remove();
}
}
}
}
Edit: step function is doing simple remove job. I move it to Game constructor
I suspect that you are getting a Concurrent Modification Exception. I would suggest you do it like this
class Action {
public void step(Game game) {
//if some condition met,
// then remove self from action stack
List<Action> tmpActionList = new List<Action>();
tmpActionList = game.actionStack
tmpActionList.remove(this);
game.actionStack = tmpActionList;
}
}
Let me know if it works.

How can i counter a ConcurrentModificationException?

if have the following problem:
I have a List which i am going through using the enhanced for loop. Every time i want to remove sth, out of the list, i get a ConcurrentModificationException. I already found out why this exception is thrown, but i don`t know how i can modify my code, so that its working. This is my code:
for(Subject s : SerData.schedule)
{
//Checking of the class is already existing
for(Classes c : s.classes)
{
if(c.day == day &c.which_class == which_class)
{
int index = getclassesindex(s.classes, new Classes(day, which_class));
synchronized (s) {
s.classes.remove(index);
}
}
}
//More code....
}
I also tried out this implementation.
for(Subject s : SerData.schedule)
{
//Checking of the class is already existing
Iterator<Classes> x = s.classes.iterator();
while(x.hasNext())
{
Classes c = x.next();
if(c.day == day &c.which_class == which_class)
{
int index = getclassesindex(s.classes, new Classes(day, which_class));
synchronized (s) {
s.classes.remove(index);
}
}
}
//More code....
}
not working either...
Is there a common used, standard solution? (Hopefully sth. that is not obvious :D )
The main reason this issue occurs is because of the semantic meaning of your for-each loop.
When you use for-each loops, the data structure that is being traversed cannot be modified.
Essentially anything of this form will throw this exception:
for( Object o : objCollection )
{
// ...
if ( satisfiesSomeProperty ( o ) )
objList.remove(o); // This is an error!!
// ...
}
As a side note, you can't add or replace elements in the collection either.
There are a few ways to perform this operation.
One way is to use an iterator and call the remove() method when the object is to be removed.
Iterator <Object> objItr = objCollection.iterator();
while(objItr.hasNext())
{
Object o = objItr.next();
// ...
if ( satifiesSomeProperty ( o ) )
objItr.remove(); // This is okay
// ...
}
This option has the property that removal of the object is done in time proportional to the iterator's remove method.
The next option is to store the objects you want to remove, and then remove them after traversing the list. This may be useful in situations where removal during iteration may produce inconsistent results.
Collection <Object> objsToRemove = // ...
for( Object o : objCollection )
{
// ...
if ( satisfiesSomeProperty ( o ) )
objsToRemove.add (o);
// ...
}
objCollection.removeAll ( objsToRemove );
These two methods work for general Collection types, but for lists, you could use a standard for loop and walk the list from the end of the list to the front, removing what you please.
for (int i = objList.size() - 1; i >= 0; i--)
{
Object o = objList.get(i);
// ...
if ( satisfiesSomeProperty(o) )
objList.remove(i);
// ...
}
Walking in the normal direction and removing could also be done, but you would have to take care of how incrementation occurs; specifically, you don't want to increment i when you remove, since the next element is shifted down to the same index.
for (int i = 0; i < objList.size(); i++)
{
Object o = objList.get(i);
// ...
if ( satisfiesSomeProperty(o) )
{
objList.remove(i);
i--;
}
//caveat: only works if you don't use `i` later here
// ...
}
Hope this provides a good overview of the concepts and helps!
Using Iterator.remove() should prevent the exception from being thrown.
Hm if I get it right you are iterating over a collection of classes and if a given class matches some criteria you are looking for the its index and try to remove it?
Why not just do:
Iterator<Classes> x = s.classes.iterator();
while(x.hasNext()){
Classes c = x.next();
if(c.day == day && c.which_class == which_class) {
x.remove();
}
}
Add synchronization if need be (but I would prefer a concurrent collection if I were you), preferably change the "==" to equals(), add getters/setters etc. Also the convention in java is to name variables and methods using camelCase (and not separating them with "_").
Actually this is one of the cases when you have to use an iterator.
From the javadoc on ConcurrentModificationException:
"if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception."
So within your
for (Classes c : s.classes)
you are executing
s.classes.remove(index)
and the iterator is doing just what its contract says. Declare the index(es) in a scope outside the loop and remove your target after the loop is done.
Iterator<Classes> classesIterator = s.classes.iterator();
while (classesIterator.hasNext()) {
Classes c = classesIterator.next();
if (c.day == day && c.which_class == which_class) {
classesIterator.remove();
}
}
There is no general solution for Collection subclasses in general - most iterators will become invalid if the collection is modified, unless the modification happens through the iterator itself via Iterator.remove().
There is a potential solution when it comes to List implementations: the List interface has index-based add/get/set/remove operations. Rather than use an Iterator instance, you can iterate through the list explicitly with a counter-based loop, much like with arrays. You should take care, however, to update the loop counter appropriately when inserting or deleting elements.
Your for-each iterator is fail-fast and this is why remove operation fails as it would change the collection while traversing it.
What implementation of List interface are you using?
Noticed synchronisation on Subject, are you using this code concurrently?
If concurrency is the case, then I would recommend using CopyOnWriteArrayList. It doesn't need synchronisation and its for-each iterator doesn't throw ConcurrentModificationException.

ArrayList remove error

I'm working on a project for school but i'm a little stuck right now
My problem is that i have an arrayList of Squares
Each Square has a value(from 0 to 100). Its starting value is 9999 so i can check if its is checked.
If a square is checked i want it to be removed from the arrayList.
So after a while there will be no Squares left.
there is a little bit of code where the first value is set so thats why i check if the value is 9999.
But i get an error. One that i havent seen before.
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
Vak = Square
this is my code:
while (!vakken.isEmpty()) { // check if empty
Iterator itrVak = vakken.iterator();
while (itrVak.hasNext()) {
Vak vak = (Vak) itrVak.next(); // here is get the error
if (vak.getValue() != 9999) {// check if square value is 9999
Collection checkVakken = vak.getNeighbour().values();
Iterator itre = checkVakken.iterator();
while (itre.hasNext()) {
Vak nextVak = (Vak) itre.next();
if (nextVak != null) {
if (nextVak.getValue() == 9999) {
nextVak.setValue(vak.getValue() + 1); // set value by its neighbour
vakken.remove(vak);
checkvakken.add(vak);
}
}
}
} else {
vakken.remove(vak);
checkvakken.add(vak);
}
}
}
You are removing elements from the collection while you are iterating it. As the iterator may produce unpredictable results in this situation, it fails fast throwing the exception you encountered.
You may only alter a collection through the iterator's methods while traversing it. There should be remove method on the iterator itself, that removes the current element and keeps the iterator intact.
While iterating, you should use Iterator instance for removing object:
itre.remove();
You can try like this:
itre.remove();
ITERATOR never lets you modify when you are iterating.. you need to use loops instead.. this happens coz you are using the Iterator, same time other thread is modifying the list...

Categories

Resources