Being somewhat new to the Java language I'm trying to familiarize myself with all the ways (or at least the non-pathological ones) that one might iterate through a list (or perhaps other collections) and the advantages or disadvantages of each.
Given a List<E> list
object, I know of the following ways to loop through all elements:
Basic for loop (of course, there're equivalent while
/ do while
loops as well)
// 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
// ...
}
Note: As @amarseillan pointed out, this form is a poor choice
for iterating over List
s, because the actual implementation of
the get
method may not be as efficient as when using an Iterator
.
For example, LinkedList
implementations must traverse all of
the elements preceding i to get the i-th element.
In the above example there's no way for the List
implementation to
"save its place" to make future iterations more efficient.
For an ArrayList
it doesn't really matter, because the complexity/cost of get
is constant time (O(1)) whereas for a LinkedList
is it proportional to the size of the list (O(n)).
For more information about the computational complexity of the built-in Collections
implementations, check out this question.
Enhanced for loop (nicely explained in this question)
for (E element : list) {
// 1 - can call methods of element
// ...
}
Iterator
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
// ...
}
Functional Java
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach, Stream.forEach, ...
(A map method from Java 8's Stream API (see @i_am_zero's answer).)
In Java 8 collection classes that implement Iterable
(for example, all List
s) now have a forEach
method, which can be used instead of the for loop statement demonstrated above. (Here is another question that provides a good comparison.)
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).
What other ways are there, if any?
(BTW, my interest does not stem at all from a desire to optimize performance; I just want to know what forms are available to me as a developer.)
List
interface specifically? – Barracksfor
loop is wrong. Inside the loop,element
is a reference to the actual list element, not a copy of it. Similarly with the iterator. You can, in fact, use all three styles to iterate over lists of singletons (or even enum values) that cannot be copied. – Puglianumbers
to change? – Corrie