Кто-нибудь может объяснить мне эту Java-ошибку? - PullRequest
1 голос
/ 15 мая 2011

Это небольшое раздражение заставило меня потерять час сна, и я не понимаю, почему.

У меня есть массив ArrayList, который я хочу перебрать и условно удалить элементы.Это была моя первая попытка:

for (int i = 0; i < array.size(); i++) {
   if (array.get(i) == conditionMet) array.remove(i);
}

И это не сработало.Сделали следующее:

for (Iterator<T> i = array.iterator(); i.hasNext();) {
   if (i.next() == conditionMet) i.remove();
}

Почему?

Ответы [ 6 ]

7 голосов
/ 15 мая 2011

Вы не указали, как это не сработало , но когда вы перебираете ArrayList в цикле for и , удаляя элемент в текущем index i, размер коллекции и индексы для последующих элементов, оба изменения, что, вероятно, того, чего вы не ожидали.

Из документации на ArrayList#remove(int index):

Удаляет элемент в указанной позиции в этом списке. Смещает любые последующие элементы влево (вычитает один из их индексов) .

1 голос
/ 15 мая 2011

Проблема в том, что вы пытаетесь изменить список, по которому вы перебираете. если вы сделали что-то вроде этого:

int listSize = array.size();
for (int i = 0; i < list; i++) {
    if (array.get(i) == conditionMet) {
        array.remove(i);
        i--;
        listSize--;
    }
}

Таким образом, вы просто итерируете до целого, а не используете размер ArrayList, который вы изменяете в теле цикла, что Java не позволяет.

Надеюсь, что это работает для вас.

1 голос
/ 15 мая 2011

Какой тип ArrayList и conditionMet?Вы не можете сравнивать объекты с == только с помощью метода .equals (который вы должны переопределить).

edit: (давно не делал Java и не уверен на 100%, будет ли это правильно,Вы должны проверить это)

Iterator<E> it = list.getIterator();
while(it.hasNext()) {
  E obj = it.next();
  if(obj.equals(VARIABLE)) {
    it.remove();
  }
}
0 голосов
/ 17 мая 2011

В первом цикле for,

for (int i = 0; i < array.size(); i++) {
   if (array.get(i) == conditionMet) array.remove(i);
}

условие ; i < array.size(); оценивается в самом начале, которое примет размер исходного списка.Таким образом, при выполнении итерации по нему, если вы удаляете из него какой-либо элемент, размер уменьшается, но вы все равно продолжаете итерацию до исходного размера, что, очевидно, неверно.

Во втором цикле for,

for (Iterator<T> i = array.iterator(); i.hasNext();) {
   if (i.next() == conditionMet) i.remove();
}

, так как вы используете итератор, вы проверяете, остался ли элемент в списке или нет.следовательно, вы не переступаете и это работает должным образом.

(Вы должны были включить исключение в вопрос. "Исключение в потоке" main "java.lang.IndexOutOfBoundsException")

0 голосов
/ 16 мая 2011

Коллекциям не нравится, когда члены удаляются из середины цикла, кроме случаев, когда это делается через итератор.

Итераторы позволяют вызывающей стороне удалять элементы из базовой коллекции во время итерации с четко определенной семантикой.

0 голосов
/ 15 мая 2011

Simple.Во втором случае i является классом итератора типа, а в первом i является целым числом.Когда вы удалите значения во время итерации, индексы изменятся (в основном, пропустите одно).Таким образом, каждый раз, когда вы удаляете, вы должны уменьшать i на единицу (что снова будет увеличиваться циклом for).Итак, изменив первый на

for (int i = 0; i < array.size(); i++) {
    if (array.get(i) == conditionMet) array.remove(i--);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...