Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (754)
Games in Android Showcase (229)
games submitted by our members
Games in WIP (842)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Removing objects from vectors  (Read 2513 times)
0 Members and 1 Guest are viewing this topic.
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Posted 2011-02-13 15:22:53 »

It doesn't work out too well.

Every time I remove an object from my vector, this happens:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
java.util.ConcurrentModificationException
        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
        at java.util.AbstractList$Itr.next(AbstractList.java:343)
        at com.javadaemon.GameEngine.EntityManager.update(EntityManager.java:42)
        at com.javadaemon.GameEngine.GameEngine.update(GameEngine.java:59)
        at org.newdawn.slick.GameContainer.updateAndRender(GameContainer.java:657)
        at org.newdawn.slick.AppGameContainer.gameLoop(AppGameContainer.java:408)
        at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:318)
        at com.javadaemon.GameEngine.GameEngine.main(GameEngine.java:75)
Sun Feb 13 16:20:07 CET 2011 ERROR:Game.update() failure - check the game code.
org.newdawn.slick.SlickException: Game.update() failure - check the game code.
        at org.newdawn.slick.GameContainer.updateAndRender(GameContainer.java:663)
        at org.newdawn.slick.AppGameContainer.gameLoop(AppGameContainer.java:408)
        at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:318)
        at com.javadaemon.GameEngine.GameEngine.main(GameEngine.java:75)
BUILD SUCCESSFUL (total time: 8 seconds)


I thought you could remove entries in vectors?

This is my code:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
public Vector<Entity> entities;

    public EntityManager() {
        entities = new Vector();
    }

public void update(int delta) {
    for (Entity e : entities) {
            e.update(delta);
            if (e instanceof Rocket) {
                Rocket rocket = (Rocket) e;
                if (rocket.isExploded) {
                    entities.remove(e);
                }
            }
        }


How do I handle vectors correctly, because in the javadocs it sais that vectors can shrink and grow as needed?

EDIT: It seems that when I tweak the update amount on the rockets the problem disappears.
This is the rocket update():
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
@Override
    public void update(int delta) {
        if (timePassed + delta > updateTime) {
            y -= 1;
            timePassed = 0;
            if (y < World.MINIMUM_EXPLODE_HEIGHT) {
                isExploded = true;
            }
        } else {
            timePassed += delta;
        }
    }


The Y int of the rocket starts at around 800, and MINIMUM_EXPLODE_HEIGHT is around 100.

This is how entities are updated:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
public void addRocket() {
        int x = generator.nextInt(GameEngine.width);
        Rocket r = new Rocket(x, 5, 20);
        entities.add(r);
    }

    public void update(int delta) {
        timePassed += delta;
        if (timePassed > addRocketTime) {
            timePassed = 0;
            addRocket();
        }
       
        for (Entity e : entities) {
            e.update(delta);
            /*if (e instanceof Rocket) {
                Rocket rocket = (Rocket) e;
                if (rocket.isExploded) {
                    entities.remove(e);
                }
            }*/

        }

        for (Entity e : entities) {
            if (e instanceof Rocket) {
                Rocket rocket = (Rocket) e;
                if (rocket.isExploded) {
                    entities.remove(e);
                }
            }
        }
    }

Offline Captain Awesome

Junior Devvie


Medals: 2


Hi


« Reply #1 - Posted 2011-02-13 15:29:46 »

You can't modify the list in the for-each loop.
Offline JL235

JGO Coder


Medals: 10



« Reply #2 - Posted 2011-02-13 15:39:39 »

When you iterate using a for-each there is secretly an iterator in the background. If you remove things from the vector whilst using the iterator, the iterator gets out of sync with your vector. The exception is deliberate to point this out, because it helps to ensure your interacting with it in a safe way.

A simple fix is to iterate using an index, incrementing it when you are not removing an element. Like...
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
public Vector<Entity> entities;
 
public EntityManager() {
    entities = new Vector();
}
 
public void update(int delta) {
    int i = 0;

    while ( i < entities.size() ) {
        Entity e = entities.get(i);
        e.update(delta);

        if (e instanceof Rocket) {
            Rocket rocket = (Rocket) e;

            if (rocket.isExploded) {
                entities.remove(i);
            } else {
                i++;
            }
        }
    }
}


Alternatively if you use an Iterator, which is the proper way to do this. Like...
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
public Vector<Entity> entities;
 
public EntityManager() {
    entities = new Vector();
}
 
public void update(int delta) {
    Iterator<Entity> it = entities.iterator();

    while ( it.hasNext() ) {
        Entity e = it.next();
        e.update(delta);

        if (e instanceof Rocket) {
            Rocket rocket = (Rocket) e;
           
            if (rocket.isExploded) {
                it.remove();
            }
        }
    }
}


A third option is to record which items you are removing and then remove them later. Sometimes this is desirable.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
public Vector<Entity> entities;
public Vector<Entity> removedEntities;
 
public EntityManager() {
    entities = new Vector<Entity>();
    removedEntities = new Vector<Entity>();
}
 
public void update(int delta) {
    for ( Entity e : entities ) {
        e.update(delta);
       
        if (e instanceof Rocket) {
            Rocket rocket = (Rocket) e;
           
            if (rocket.isExploded) {
                removedEntities.add( e );
            }
        }
    }
   
    entities.removeAll( removedEntities );
    removedEntities.clear();
}


All code posted above is untested, but I hope that helps!

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #3 - Posted 2011-02-13 15:43:23 »

When you iterate using a for-each there is secretly an iterator in the background. If you remove things from the vector whilst using the iterator, the iterator gets out of sync with your vector. The exception is deliberate to point this out, because it helps to ensure your interacting with it in a safe way.

A simple fix is to iterate using an index, incrementing it when you are not removing an element. Like...
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
public Vector<Entity> entities;
 
public EntityManager() {
    entities = new Vector();
}
 
public void update(int delta) {
    int i = 0;

    while ( i < entities.size() ) {
        Entity e = entities.get(i);
        e.update(delta);

        if (e instanceof Rocket) {
            Rocket rocket = (Rocket) e;

            if (rocket.isExploded) {
                entities.remove(i);
            } else {
                i++;
            }
        }
    }
}


Alternatively if you use an Iterator, which is the proper way to do this. Like...
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
public Vector<Entity> entities;
 
public EntityManager() {
    entities = new Vector();
}
 
public void update(int delta) {
    Iterator<Entity> it = entities.iterator();

    while ( it.hasNext() ) {
        Entity e = it.next();
        e.update(delta);

        if (e instanceof Rocket) {
            Rocket rocket = (Rocket) e;
           
            if (rocket.isExploded) {
                it.remove();
            }
        }
    }
}


A third option is to record which items you are removing and then remove them later. Sometimes this is desirable.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
public Vector<Entity> entities;
public Vector<Entity> removedEntities;
 
public EntityManager() {
    entities = new Vector<Entity>();
    removedEntities = new Vector<Entity>();
}
 
public void update(int delta) {
    for ( Entity e : entities ) {
        e.update(delta);
       
        if (e instanceof Rocket) {
            Rocket rocket = (Rocket) e;
           
            if (rocket.isExploded) {
                removedEntities.add( e );
            }
        }
    }
   
    entities.removeAll( removedEntities );
    removedEntities.clear();
}


All code posted above is untested, but I hope that helps!

Ahh.. That did the trick!  Cheesy Thank you very much.
Appriciate+

Offline tom
« Reply #4 - Posted 2011-02-13 17:03:58 »

Or you could use a CopyOnWriteArrayList

Offline JL235

JGO Coder


Medals: 10



« Reply #5 - Posted 2011-02-13 20:35:23 »

Or you could use a CopyOnWriteArrayList
That would be much more expensive then you need it to be.

Offline tom
« Reply #6 - Posted 2011-02-14 10:39:11 »

It depends on how often you change the list.

But I have to admit I try my best to suppress my urges to optimize. I try to write the easiest, most readable code I can, unless I'm absolutely sure there will be a performance problem.

Offline JL235

JGO Coder


Medals: 10



« Reply #7 - Posted 2011-02-14 13:16:28 »

It depends on how often you change the list.

But I have to admit I try my best to suppress my urges to optimize. I try to write the easiest, most readable code I can, unless I'm absolutely sure there will be a performance problem.
Normally I'd agree and advocate the same argument, but using an iterator (or one of the other alternatives I've suggested) instead of a CopyOnWriteArrayList isn't going to make the code that much different or less redable.

Pages: [1]
  ignore  |  Print  
 
 

 
DesertCoockie (20 views)
2018-05-13 18:23:11

nelsongames (68 views)
2018-04-24 18:15:36

nelsongames (65 views)
2018-04-24 18:14:32

ivj94 (748 views)
2018-03-24 14:47:39

ivj94 (79 views)
2018-03-24 14:46:31

ivj94 (595 views)
2018-03-24 14:43:53

Solater (95 views)
2018-03-17 05:04:08

nelsongames (168 views)
2018-03-05 17:56:34

Gornova (378 views)
2018-03-02 22:15:33

buddyBro (1038 views)
2018-02-28 16:59:18
Java Gaming Resources
by philfrei
2017-12-05 19:38:37

Java Gaming Resources
by philfrei
2017-12-05 19:37:39

Java Gaming Resources
by philfrei
2017-12-05 19:36:10

Java Gaming Resources
by philfrei
2017-12-05 19:33:10

List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!