Будучи несколько новым для языка Java, я пытаюсь ознакомиться со всеми способами (или, по крайней мере, непатологическими), которые можно перебирать через список (или, возможно, другие коллекции), а также преимущества или недостатки каждого из них.
Учитывая List<E> list
, мне известны следующие способы циклического перемещения по всем элементам:
Базовый для цикла (конечно, есть эквивалент while
/do while
)
// Not recommended (see below)!
for (int i = 0; i < list.size(); i++) {
E element = list.get(i);
// 1 - can call methods of element
// 2 - can use 'i' to make index-based calls to methods of list
// ...
}
Примечание. Как отметил @amarseillan, эта форма является плохим выбором для итерации над List
s, потому что фактическая реализация метода get
может быть не такой эффективной, как при использовании Iterator
. Например, реализация LinkedList
должна пересекать все элементы, предшествующие i, чтобы получить i-й элемент.
В приведенном выше примере для реализации List
возможности "сохранить свое место", чтобы сделать будущие итерации более эффективными. Для ArrayList
это не имеет большого значения, поскольку сложность/стоимость get
- это постоянное время (O (1)), тогда как для LinkedList
оно пропорционально размеру списка (O (n)).
Для получения дополнительной информации об вычислительной сложности встроенных реализаций Collections
ознакомьтесь с этим вопросом.
Улучшено для цикла (хорошо объяснено в этом вопросе)
for (E element : list) {
// 1 - can call methods of element
// ...
}
Итератор
for (Iterator<E> iter = list.iterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// ...
}
ListIterator
for (ListIterator<E> iter = list.listIterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// 3 - can use iter.add(...) to insert a new element into the list
// between element and iter->next()
// 4 - can use iter.set(...) to replace the current element
// ...
}
Функциональная Java
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach, Stream.forEach ,...
(Метод карты из Java 8 Stream API (см. Ответ @i_am_zero).)
В классах классов Java 8, которые реализуют Iterable
(например, все List
s), теперь есть метод forEach
, который можно использовать вместо приведенного выше оператора цикла for. (Вот еще один вопрос, который дает хорошее сравнение.)
Arrays.asList(1,2,3,4).forEach(System.out::println);
// 1 - can call methods of an element
// 2 - would need reference to containing object to remove an item
// (TODO: someone please confirm / deny this)
// 3 - functionally separates iteration from the action
// being performed with each item.
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
// Same capabilities as above plus potentially greater
// utilization of parallelism
// (caution: consequently, order of execution is not guaranteed,
// see [Stream.forEachOrdered][stream-foreach-ordered] for more
// information about this).
Какие существуют другие способы, если они есть?
(Кстати, мой интерес отнюдь не сводится к желанию оптимизировать производительность, я просто хочу знать, какие формы доступны мне как разработчику.)