Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Обход коллекций

Почти любая работа с коллекцией сводится к обходу её элементов: вывести, посчитать, отфильтровать. В Java для этого есть несколько способов, и у каждого своё место.

Цикл for-each

Самый простой способ — цикл for-each. Он работает с любой коллекцией: списком, множеством, очередью:

void main() {
    List<String> names = List.of("Анна", "Олег", "Ира");
    for (String name : names) {
        IO.println("Привет, " + name);
    }
}

Результат:

Привет, Анна
Привет, Олег
Привет, Ира

Читается он так: «для каждого name из names».

Обход по индексу

Если нужен номер элемента, используют обычный цикл for с индексом. Это работает только для списков — у множества индексов нет:

void main() {
    List<String> places = List.of("Анна", "Олег", "Ира");
    for (int i = 0; i < places.size(); i++) {
        IO.println((i + 1) + " место: " + places.get(i));
    }
}

Результат:

1 место: Анна
2 место: Олег
3 место: Ира

Метод forEach()

У каждой коллекции есть метод forEach(). Ему передают действие в виде лямбды — короткой записи функции: слева от стрелки параметр, справа то, что с ним сделать:

void main() {
    List<Integer> prices = List.of(10, 25, 7);
    prices.forEach(price -> IO.println(price + " €"));
}

Результат:

10 €
25 €
7 €

Лямбды подробно разобраны в следующей главе, пока достаточно этой формы.

Обход словаря

Словарь — не коллекция элементов, а набор пар. Можно перебрать только ключи (keySet()), только значения (values()) или пары целиком. Удобнее всего — forEach() с двумя параметрами:

void main() {
    Map<String, Integer> scores = new TreeMap<>(Map.of("Олег", 75, "Анна", 90));
 
    for (String name : scores.keySet()) {
        IO.println(name);
    }
    scores.forEach((name, score) -> IO.println(name + " → " + score));
}

Результат:

Анна
Олег
Анна → 90
Олег → 75

Удаление при обходе

Чтобы удалить элементы по условию, у коллекций есть метод removeIf(). Он принимает условие и сам удаляет все подходящие элементы:

void main() {
    List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
    numbers.removeIf(n -> n % 2 == 0);
    IO.println(numbers);
}

Результат:

[1, 3, 5]

Более старый способ — объект Iterator: его методы hasNext() и next() перебирают элементы, а remove() безопасно удаляет текущий. Как написать свой итератор и научить for-each перебирать ваш класс, показано в уроке свой Iterable.

Частая ошибка

Внутри цикла for-each нельзя удалять элементы из той же коллекции. Список замечает, что его изменили во время обхода, и выбрасывает исключение:

void main() {
    List<String> items = new ArrayList<>(List.of("хлеб", "молоко", "сыр", "чай"));
    for (String item : items) {
        if (item.equals("молоко")) {
            items.remove(item);
        }
    }
}

Результат:

Exception in thread "main" java.util.ConcurrentModificationException

Используйте items.removeIf(item -> item.equals("молоко")) или Iterator с его методом remove().

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.