Java: NoSuchElementException при повторении через ArrayList

Я хочу удалить повторяющиеся элементы и, следовательно, перебрать ArrayList и сравнить два последовательных элемента. (лица сопоставимы)

ArrayList<Person> persons = getHelper().findAllPersons();
Collections.sort(persons);
ListIterator<Person> it = persons.listIterator();
if(it.hasNext()) {
    Person tmp = it.next();
    while(it.hasNext()) {
        if(tmp.getLastDiscovered() == it.next().getLastDiscovered()) {
            getHelper().delete(tmp);
        }
    tmp = it.next();
    }
}

Я получаю исключение NoSuchElementException в tmp = it.next();

Разве while(it.hasNext()) не должно этому препятствовать?


person ArtVandelay    schedule 10.05.2013    source источник
comment
final Set<Person> unqiuePeople = new TreeSet<Person>(persons) сделает то, что вы хотите, в одной строке.   -  person Boris the Spider    schedule 10.05.2013
comment
С правильно определенным методом comparator/equals()   -  person Brian Agnew    schedule 10.05.2013
comment
@BrianAgnew, учитывая, что OP уже использует Collections.sort для заказа элементов, я предполагаю, что это уже определено.   -  person Boris the Spider    schedule 10.05.2013


Ответы (4)


Проблема в том, что вы вызываете it.next() дважды, что увеличивает итератор в два раза.

Вы должны сохранить значение, чтобы избежать повторения побочного эффекта.

    Person person = it.next();
    if (tmp.getLastDiscovered() == person.getLastDiscovered()) {
        getHelper().delete(tmp);
    }
    tmp = person;

В качестве альтернативы вы можете использовать цикл for-each, чтобы избежать необходимости взаимодействовать с итераторами (я предполагаю, что все Person не равны нулю):

Person tmp = null;
for (Person person : persons) {
    if (tmp != null && tmp.getLastDiscovered() == person.getLastDiscovered()) {
        getHelper().delete(tmp);
    }
    tmp = person;
}
person kennytm    schedule 10.05.2013

Вы вызываете it.next() дважды (потенциально) для каждого вызова it.hasNext(), отсюда и ваша ошибка.

Если вы хотите удалить дубликаты, почему бы просто не заполнить TreeSet (указав соответствующий компаратор) с вашим списком? Семантика Set такова, что у вас будет отдельный набор элементов.

person Brian Agnew    schedule 10.05.2013

Если вы используете JDK 1.5.0 или более позднюю версию (что, скорее всего, так и есть, поскольку она была выпущена в 2004 г.), вы можете использовать цикл foreach, чтобы полностью отказаться от итератора, что значительно упрощает код.

ArrayList<Person> persons = getHelper().findAllPersons();
Collections.sort(persons);
for (Person person : persons) {
    if(tmp.getLastDiscovered() == person.getLastDiscovered()) {
        getHelper().delete(tmp);
    }
}
person Drew Stephens    schedule 10.05.2013

while(it.hasNext()) {
        if(tmp.getLastDiscovered() == it.next().getLastDiscovered()) {
            getHelper().delete(tmp);
        }

После этого «пока» вы подходите к концу списка. Затем, когда у него нет следующего значения, вы вызываете строку ниже.

tmp = it.next();

Это дает вам исключение.

person bkrcinar    schedule 10.05.2013