2

I have a problem while going through this iterator loop, in which i go through each element of this.env, but within this list, wanting to remove a different element of said list. When I try to remove any item of said iterating list, I receive this error: java.util.ConcurrentModificationException, and as far as I understand this is caused due to modifying the iterating list without using iterator.remove().

Code:

public void envActions(IOHandler ioHandler, PlayerClass player){
    Iterator<WorldElement> worldElementIterator = this.env.iterator();
    while(worldElementIterator.hasNext()){
        WorldElement worldElement = worldElementIterator.next();
    //for(WorldElement worldElement:this.env){
        if(worldElement instanceof EntityClass){
            EntityClass entity=(EntityClass) worldElement;
            if(entity.nature.contains("hostile")){
                MonsterClass mEntity=(MonsterClass) entity;
                if(!(mEntity.attacks.size()*(Math.random()+0.25)>=mEntity.attacks.size())){
                    Double followerNum = (Math.random()*player.followers.size());
                    Integer followerNumInt=followerNum.intValue();
                    if(followerNumInt<2){
                        PlayerClass target=player;
                        Double attacknumD=mEntity.attacks.size()*Math.random();
                        Integer attacknum= attacknumD.intValue();
                        Integer playerarmor=player.getArmorValue();
                        int enemydamage=mEntity.attacks.get(attacknum).getDamage()*(1-(playerarmor/1000));
                        target.health=target.health-enemydamage;
                        ioHandler.printToConsole("\nThe "+mEntity.name+" attacked you with "+mEntity.attacks.get(attacknum).getAttack()+" and did "+mEntity.attacks.get(attacknum).getDamage()+" damage! you have "+player.health+" health left!");
                    } else {
                        FriendlyCreatureClass target=player.followers.get(followerNumInt);
                        Double attacknumD=mEntity.attacks.size()*Math.random();
                        Integer attacknum= attacknumD.intValue();
                        int enemydamage=mEntity.attacks.get(attacknum).getDamage();
                        target.health=target.health-enemydamage;
                        if(!target.isAlive()){
                            ioHandler.printToConsole("\nThe " + mEntity.name + " attacked " + target.name + " with " + mEntity.attacks.get(attacknum).getAttack() + " and did " + mEntity.attacks.get(attacknum).getDamage() + " damage! " + target.name+" died! Farewell "+target.name+".");
                            target.died(ioHandler, this, player, true);
                            //>>>> THIS IS WHERE I WOUlD LIKE TO REMOVE 'target' FROM THE env LIST <<<<
                        } else {
                            ioHandler.printToConsole("\nThe "+mEntity.name+" attacked "+target.name+" with "+mEntity.attacks.get(attacknum).getAttack()+" and did "+mEntity.attacks.get(attacknum).getDamage()+" damage! "+target.name+" has "+target.health+" health left!");
                        }
                    }
                }

Please have mercy with my coding skills, since I am only a beginner in java / Android, though any suggestions are greatly appreciated!

Thanks in advance!

5
  • why haven't you tried worldElementIterator.remove() ? Commented Mar 30, 2016 at 22:03
  • Wouldn't that remove the iterator itself? I want to remove a custom element in the list... Commented Mar 30, 2016 at 22:04
  • No I answered below for you. It removes the most recently accessed element, in your case worldElement is removed from the collection. The iterator isn't removed, it's the element. Commented Mar 30, 2016 at 22:08
  • You are trying to remove an element (target) that is different from the Iterator's current element (worldElement). This is quite an unusual situation. How do these elements relate to each other in the list? E.g. is target always to the left of worldElement? Commented Mar 30, 2016 at 22:10
  • @PaulBoddington yes exactly that's my problem, and no the target is being randomly selected... Commented Mar 30, 2016 at 22:12

2 Answers 2

1

If you are NOT using Iterator for whatever reason, you can collect the elements to be deleted in a Set when you are iterating over the collection, and after the loop you iterate over the Set and delete the elements from the original collection.

Note that this is only workable for small-sized collections.

HashSet toDelete = new HashSet();

for (...) {
    if (...)
       toDelete.add(item);
}
// end for

foreach (item in toDelete) {
    // delete from original collection
}

Otherwise, you can just call remove() on the iterator.

Sign up to request clarification or add additional context in comments.

5 Comments

But if i don't remove the elements that need to be removed after every loop round, it will trigger the loop again and execute the actions even though it should not even exist?
He shouldn't do this, it makes no sense. If he is already using an Iterator, just utilize the correct functionality
@LucasCrawford Iterator.remove() won't work if you're not removing the element that was just visited in the iteration.
@TheFloppyToast then you should also check if the element is in toDelete and skip it in the iteration process. This really is probably the only way you're going to be able to solve your problem.
@LouisWasserman yep that worked! if you are curious, I posted the working code snippet below
0

I think it works now with adding a toDelete list, checking if the iterating item is already in the list, if it is, then skip it, and afterwards deleting it.

I haven't thoroughly checked for bugs, but for now it's fine. Working code:

public void envActions(IOHandler ioHandler, PlayerClass player){
    List<WorldElement> toDelete=new ArrayList<>();
    Iterator<WorldElement> worldElementIterator = this.env.iterator();
    while(worldElementIterator.hasNext()){
        WorldElement worldElement = worldElementIterator.next();
    //for(WorldElement worldElement:this.env){
        if(worldElement instanceof EntityClass && !toDelete.contains(worldElement)){
            EntityClass entity=(EntityClass) worldElement;
            if(entity.nature.contains("hostile")){
                MonsterClass mEntity=(MonsterClass) entity;
                if(!(mEntity.attacks.size()*(Math.random()+0.25)>=mEntity.attacks.size())){
                    Double followerNum = (Math.random()*player.followers.size());
                    Integer followerNumInt=followerNum.intValue();
                    if(followerNumInt<2){
                        PlayerClass target=player;
                        Double attacknumD=mEntity.attacks.size()*Math.random();
                        Integer attacknum= attacknumD.intValue();
                        Integer playerarmor=player.getArmorValue();
                        int enemydamage=mEntity.attacks.get(attacknum).getDamage()*(1-(playerarmor/1000));
                        target.health=target.health-enemydamage;
                        ioHandler.printToConsole("\nThe "+mEntity.name+" attacked you with "+mEntity.attacks.get(attacknum).getAttack()+" and did "+mEntity.attacks.get(attacknum).getDamage()+" damage! you have "+player.health+" health left!");
                    } else {
                        FriendlyCreatureClass target=player.followers.get(followerNumInt);
                        Double attacknumD=mEntity.attacks.size()*Math.random();
                        Integer attacknum= attacknumD.intValue();
                        int enemydamage=mEntity.attacks.get(attacknum).getDamage();
                        target.health=target.health-enemydamage;
                        if(!target.isAlive()){
                            ioHandler.printToConsole("\nThe " + mEntity.name + " attacked " + target.name + " with " + mEntity.attacks.get(attacknum).getAttack() + " and did " + mEntity.attacks.get(attacknum).getDamage() + " damage! " + target.name + " died! Farewell " + target.name + ".");
                            target.died(ioHandler, this, player, false);
                            toDelete.add(target);
                        } else {
                            ioHandler.printToConsole("\nThe "+mEntity.name+" attacked "+target.name+" with "+mEntity.attacks.get(attacknum).getAttack()+" and did "+mEntity.attacks.get(attacknum).getDamage()+" damage! "+target.name+" has "+target.health+" health left!");
                        }
                    }
                }
    for(WorldElement worldElement:toDelete){
        this.env.remove(worldElement);
    }
    return;

Thanks for the fast responses!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.