Iterating over collections
Almost any work with a collection comes down to going through its elements: print them, count them, filter them. Java has several ways to do this, and each has its place.
The for-each loop
The simplest way is the for-each loop. It works with any collection: a list, a set, a queue:
void main() {
List<String> names = List.of("Anna", "Oleg", "Ira");
for (String name : names) {
IO.println("Hello, " + name);
}
}Output:
Hello, Anna
Hello, Oleg
Hello, IraIt reads like this: "for each name in names".
Iterating by index
If you need the element's number, use an ordinary for loop with an index. This works only for lists — a set has no indexes:
void main() {
List<String> places = List.of("Anna", "Oleg", "Ira");
for (int i = 0; i < places.size(); i++) {
IO.println("Place " + (i + 1) + ": " + places.get(i));
}
}Output:
Place 1: Anna
Place 2: Oleg
Place 3: IraThe forEach() method
Every collection has a forEach() method. You pass it an action in the form of a lambda — a short way to write a function: the parameter on the left of the arrow, what to do with it on the right:
void main() {
List<Integer> prices = List.of(10, 25, 7);
prices.forEach(price -> IO.println(price + " €"));
}Output:
10 €
25 €
7 €Lambdas are covered in detail in the next chapter; for now this form is enough.
Iterating a map
A map is not a collection of elements but a set of pairs. You can go through only the keys (keySet()), only the values (values()) or whole pairs. The most convenient way is forEach() with two parameters:
void main() {
Map<String, Integer> scores = new TreeMap<>(Map.of("Oleg", 75, "Anna", 90));
for (String name : scores.keySet()) {
IO.println(name);
}
scores.forEach((name, score) -> IO.println(name + " → " + score));
}Output:
Anna
Oleg
Anna → 90
Oleg → 75Removing while iterating
To remove elements by a condition, collections have the removeIf() method. It takes a condition and removes all matching elements by itself:
void main() {
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
numbers.removeIf(n -> n % 2 == 0);
IO.println(numbers);
}Output:
[1, 3, 5]An older way is an Iterator object: its hasNext() and next() methods go through the elements, and remove() safely deletes the current one. How to write your own iterator so that for-each can loop over your class is shown in the your own Iterable lesson.
Common mistake
Inside a for-each loop you cannot remove elements from the same collection. The list notices that it was changed during iteration and throws an exception:
void main() {
List<String> items = new ArrayList<>(List.of("bread", "milk", "cheese", "tea"));
for (String item : items) {
if (item.equals("milk")) {
items.remove(item);
}
}
}Output:
Exception in thread "main" java.util.ConcurrentModificationExceptionUse items.removeIf(item -> item.equals("milk")) or an Iterator with its remove() method.