Будучи немного новым для языка 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
реализация не может "сохранить свое место", чтобы сделать будущие итерации более эффективными. Для a ArrayList
это на самом деле не имеет значения, потому что сложность / стоимость get
является постоянным временем (O (1)), тогда как для a 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 , ...
(Метод карты из Stream API Java 8 (см. Ответ @ i_am_zero).)
В Java 8 классы коллекций, которые реализуют Iterable
(например, все List
), теперь имеют 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).
Какие еще есть способы, если таковые имеются?
(Кстати, мой интерес совсем не связан с желанием оптимизировать производительность ; я просто хочу знать, какие формы доступны мне как разработчику.)
List
интерфейсе конкретно?