for (int i = 0; i < books.size(); i++) {
Book book = books.get(i);
// do something with book
}
This is quite error prone, because there are several places it is possible to make a mistake. For example, is the first element stored at place 0 or place 1? Should i be less than the books.size() or less or equal than the books.size()? Also, the loop will never terminate if one forgets to icrement i.
A somewhat better solution is, to use an iterator.
for (Iterator it = books.iterator(); it.hasNext(); ) {
Book book = it.next();
// do something with book
However, the solution is still rather verbose and contains possibilities for errors.
The recommended way to iterate over a list is:
for (Book book : books) {
// do something with book
}
The solution is very simple an elegant and there is not much opportunity to make a mistake.
Java 8 has introduced lambda expressions, which means one can now use more advanced features on collections and can also easily introduce new types of iterators oneself. A bascic for-loop can be now written as the following:
books.stream().forEach( b -> { /* do something */ });
However, streams have more advanced features than just iterating over a list, e.g., there are methods to select only the elements one wants to have. Consider an implementation of a findBook(String name) operation in Java 7.
public Book findBook(String name) {
for (Book book : books) {
if (book.getName().equals(name)) {
return book;
}
}
return null;
}
versus an implementation in Java 8:
public Book findBook(String name) {
Optional r = books
.stream()
.filter(b -> b.getName().equals(name))
.findFirst();
return r.isPresent() ? r.get() : null;
}
Part of Collections
Hubert Baumeister
April 23, 2018