Удаление элемента из самого внутреннего вложенного итератора в java вызывает NoSuchElementException

Я продолжаю падать и получаю java.util.NoSuchElementException в операторе if. У меня сложилось впечатление, что while(Iterator.hasNext()) гарантирует, что вызов Iterator.next() не приведет к переполнению буфера.

Каков правильный алгоритм для перебора двух вложенных итераторов и удаления элементов из одного из итераторов при обнаружении совпадения без создания такого исключения (которое, как я думаю, вызвано выходом за границы массива) ?

введите код сюда {

    Iterator<Integer> d = entitiesDeleteQueue.iterator();
    Iterator<Entity> e = entities.iterator();


    while (d.hasNext()) {

        while (e.hasNext()) {

            if (d.next() == e.next().getEntityId())

                e.remove();
        }   
    }
}

person CptHowdyRD0    schedule 26.07.2016    source источник
comment
Вы должны точно знать, что произойдет, если entities будет иметь три элемента, а entitiesDeleteQueue — два. Вы можете запустить его на бумаге.   -  person Thorbjørn Ravn Andersen    schedule 26.07.2016
comment
d.next() будет переполнен на последней итерации e.hasNext(). Спасибо.   -  person CptHowdyRD0    schedule 26.07.2016
comment
Кроме того, я вижу, что продвигаю самый внешний итератор внутри цикла каждый раз, когда вызывается next(). Эффект, который мне нужен, — это эффект вложенного цикла for, где каждая итерация внешнего цикла сравнивает один внешний элемент с каждым внутренним элементом. Для этого мне пришлось бы вызывать элемент итератора внешнего цикла, не продвигая его вперед, пока я нахожусь во внутреннем цикле. Есть ли способ добиться этого?   -  person CptHowdyRD0    schedule 26.07.2016


Ответы (2)


Вам нужно объединить два ваших условия hasNext, чтобы избежать переполнения любого итератора:

while (d.hasNext() && e.hasNext()) {
    if (d.next() == e.next.getEntityId())
        e.remove();
}
person sprinter    schedule 26.07.2016

Проблема в том, что вложение итераторов не так просто, как вложение циклов for. Требуется присвоить Iterator.next() ссылке на объект, чтобы итератор не продвигался вперед каждый раз, когда вам нужно получить доступ к элементу. Ссылка должна быть сделана в каждом слое гнезда, а второй итератор должен быть создан внутри внешнего цикла. Затем вы можете выполнять операции, не перегружая ArrayList слишком большим количеством вызовов next().

List<Entity> entities = new ArrayList<Entity>();
List<Entity> entityDeleteQueue = new ArrayList<Entity>(); 

Iterator<Entity> e = entities.iterator();

    while (e.hasNext()) {

        Entity liveEntity = e.next();
        Iterator<Entity> d = entityDeleteQueue.iterator();

        while (d.hasNext()) {

            Entity deadEntity = d.next();

            if( deadEntity.getEntityId() == liveEntity.getEntityId()){

                System.out.println("Dead entity: " + deadEntity.getEntityId());

                System.out.println("Removing entity " + liveEntity.getEntityId());

                e.remove();
            }
        }
    }

    for (Entity survivor: entities){

        System.out.println("Remaining entity: " + survivor.getEntityId());
    }
person CptHowdyRD0    schedule 26.07.2016