JAVA – удаление элемента без итератора из итерирующего списка

У меня есть проблема при прохождении этого цикла итератора, в котором я просматриваю каждый элемент this.env, но в этом списке, желая удалить другой элемент указанного списка. Когда я пытаюсь удалить любой элемент указанного итерируемого списка, я получаю эту ошибку: java.util.ConcurrentModificationException, и, насколько я понимаю, это вызвано изменением итерирующего списка без использования iterator.remove ().

Код:

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!");
                        }
                    }
                }

Пожалуйста, пощадите мои навыки кодирования, так как я только новичок в java/Android, хотя любые предложения очень ценятся!

Заранее спасибо!


person TheFloppyToast    schedule 30.03.2016    source источник
comment
почему вы не пробовали worldElementIterator.remove()?   -  person Lucas Crawford    schedule 31.03.2016
comment
Разве это не удалит сам итератор? Я хочу удалить пользовательский элемент в списке...   -  person TheFloppyToast    schedule 31.03.2016
comment
Нет, я ответил ниже для вас. Он удаляет самый последний доступный элемент, в вашем случае worldElement удаляется из коллекции. Итератор не удаляется, это элемент.   -  person Lucas Crawford    schedule 31.03.2016
comment
Вы пытаетесь удалить элемент (target), который отличается от текущего элемента Iterator (worldElement). Это довольно необычная ситуация. Как эти элементы соотносятся друг с другом в списке? Например. target всегда слева от worldElement?   -  person Paul Boddington    schedule 31.03.2016
comment
@PaulBoddington да, именно в этом моя проблема, и цель не выбирается случайным образом...   -  person TheFloppyToast    schedule 31.03.2016


Ответы (2)


Если вы НЕ используете итератор по какой-либо причине, вы можете собрать элементы, которые будут удалены, в наборе, когда вы выполняете итерацию по коллекции, а после цикла вы выполняете итерацию по набору и удаляете элементы из исходной коллекции.

Обратите внимание, что это работает только для небольших коллекций.

HashSet toDelete = new HashSet();

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

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

В противном случае вы можете просто вызвать метод remove() для итератора.

person amahfouz    schedule 30.03.2016
comment
Но если я не удалю элементы, которые необходимо удалить после каждого цикла цикла, он снова вызовет цикл и выполнит действия, даже если он даже не должен существовать? - person TheFloppyToast; 31.03.2016
comment
Он не должен этого делать, в этом нет смысла. Если он уже использует итератор, просто используйте правильную функциональность - person Lucas Crawford; 31.03.2016
comment
@LucasCrawford Iterator.remove() не будет работать, если вы не удаляете элемент, который только что был посещен в итерации. - person Louis Wasserman; 31.03.2016
comment
@TheFloppyToast, тогда вам также следует проверить, находится ли элемент в toDelete, и пропустить его в процессе итерации. Это действительно, вероятно, единственный способ решить вашу проблему. - person Louis Wasserman; 31.03.2016
comment
@LouisWasserman да, это сработало! если вам интересно, я разместил фрагмент рабочего кода ниже - person TheFloppyToast; 31.03.2016

Я думаю, что теперь это работает с добавлением списка toDelete, проверкой, есть ли итерирующий элемент уже в списке, если он есть, то пропустить его, а затем удалить.

На ошибки не проверял, но пока все нормально. Рабочий код:

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;

Спасибо за быстрые ответы!

person TheFloppyToast    schedule 30.03.2016