简体   繁体   中英

Attempting to remove element from ArrayList

I'm attempting to create a class which will display text for a couple of seconds and then disappear.

I'm using LWJGL and in my main class MetalCLicker i have a for loop which cycles through the popups.

            for(PopUp pop: popups){
            pop.tick(pop);
        }

popup class: (problem at bottom in tick method) public class PopUp {

MetalClicker game;

int x;
float y, lifetime;
String line1, line2, line3;
Color color;

private UnicodeFont font;


public PopUp(MetalClicker game, int x, int y, float lifetime, String line1, String line2, String line3, Color color){
    this.x = x;
    this.y = y;
    this.lifetime = lifetime*game.fps;
    this.line1 = line1;
    this.line2 = line2;
    this.line3 = line3;
    this.color = color;
    this.game = game;


    font = new UnicodeFont(new java.awt.Font ("Vani", Font.BOLD, 12));
    font.getEffects().add(new ColorEffect(java.awt.Color.white));
    font.addNeheGlyphs();
    try {
        font.loadGlyphs();
    } catch (SlickException e) {
        e.printStackTrace();
    }
}

public void render(){
    font.drawString(x - (line1.length()/2), y, line1, color);
    font.drawString(x - (line2.length()/2), y+14, line2, color);
    font.drawString(x - (line3.length()/2), y+28, line3, color);
}

public void tick(PopUp pop){
    y -= 3/lifetime;

    lifetime -= 1;
    if (lifetime == 0) game.popups.remove(pop); //problem resides here
    else render();
}
}

The program crashes when lifetime hits 0, thus attempting to remove the element. Putting prints before and after the remove line successfully prints out the line, So I'm confused now :(

I have tried using this in the tick method so i switched to sending the actual element in the parameter.

There is no error in the console, but the debug tells me ArrayList$Itr.next() line: 831 ArrayList$Itr.checkForComodification() line: 859 [local variables unavailable]

inside Thread [main]

I'll update post with more info if needed, but i cant think of what to say to help you, help me.

And info on how i can go about without using MetalCLicker game in my method parameters would be cool.

you're trying to remove elements while iterating through the list, thus invalidating the iterator. You cannot use this:

for(PopUp pop: popups) {
  popups.remove(pop); // effectively, due to tick
}

or even, safely, this:

for(var i=0, last=popups.size(); i<last; i++) {
  PopUp pop = popups.get(i);
  popups.remove(pop); // next "i++" will skip over an item
}

However, you CAN use this:

for(var i=popups.size()-1; i>=0; i--) {
  PopUp pop = popups.get(i);
  popups.remove(pop);
}

because any removals now happen in the part of the array list that will not be touched by the next iteration

You can't loop around a collection and remove an item directly from it at the same time. You have two options here, you can copy this collection to a new collection for the loop alone or you can, instead of using a foreach , use the collection iterator directly and send the iterator as a parameter to the tick method, then you can call the remove method at the collection iterator and it won't throw this exception.

So it's either change the foreach to:

for(PopUp pop : popups.clone()){
    pop.tick(pop);
}

Or use an iterator instead of a foreach:

Iterator<PopUp> iterator = popups.iterator();
while ( iterator.hasNext() ) {
  PopUp pop = iterator.next();
  pop.tick(iterator);
}

And at the tick implementation:

public void tick(Iterator it){
    y -= 3/lifetime;

    lifetime -= 1;
    if (lifetime == 0) {
      it.remove();
    }
    else render();
}

Both have mostly the same effect, but I'd say the second option is better.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM