Что такое цикл for-each в Java и как он работает?

Ответ

Цикл for-each (enhanced for loop) — это синтаксическая конструкция в Java для итерации по элементам массивов или коллекций, реализующих интерфейс Iterable. Он устраняет необходимость явного использования индексов или итераторов в простых случаях.

Синтаксис:

for (Type element : iterableOrArray) {
    // работа с element
}

Примеры:

  1. Итерация по массиву:

    int[] numbers = {1, 2, 3, 4, 5};
    for (int num : numbers) {
    System.out.println(num * 2); // Выведет: 2, 4, 6, 8, 10
    }
  2. Итерация по коллекции:

    List<String> names = List.of("Alice", "Bob", "Charlie");
    for (String name : names) {
    System.out.println("Hello, " + name);
    }

Ключевые особенности и ограничения:

  • Поддерживаемые типы: Работает с массивами и любыми объектами, реализующими интерфейс java.lang.Iterable (все стандартные коллекции из java.util).
  • Только для чтения: Не предоставляет доступа к текущему индексу. Попытка удалить или добавить элемент в коллекцию во время итерации приведёт к ConcurrentModificationException.
  • Производительность: Для массивов компилируется в обычный цикл for с индексом. Для коллекций использует вызов iterator(), hasNext() и next().

Когда использовать? Для простого последовательного обхода всех элементов. Для модификации коллекции или когда нужен индекс, используйте явный Iterator или классический цикл for.

Ответ 18+ 🔞

Давай разберём эту штуку, которая выглядит как обычный for, но с двоеточием посередине, будто кто-то его переел и сейчас блеванёт. Цикл for-each, он же "усиленный" — усиленный ровно настолько, чтобы не писать лишнего кода и не выёбываться с индексами, когда они не нужны.

Выглядит он вот так, запомни раз и навсегда:

for (ТипЭлемента одинЭлемент : твойМассивИлиКоллекция) {
    // Делай с этим элементом что хочешь
}

Пример первый, с массивом:
Допустим, у тебя есть массив чисел, и ты хочешь их все на экран вывалить, умножив на два. Раньше бы ты писал как конченый, с индексом i:

int[] numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
    System.out.println(num * 2); // Будет: 2, 4, 6, 8, 10
}

Видишь? Никакого numbers[i], никакого счётчика. Просто берёшь каждый элемент по имени num и работаешь с ним. Красота, ёпта!

Пример второй, с коллекцией (списком):
Тут вообще магия. Раньше надо было итератор вызывать, hasNext() проверять — пиздец, а не жизнь. А теперь:

List<String> names = List.of("Алиса", "Боб", "Чарли");
for (String name : names) {
    System.out.println("Привет, " + name);
}

Всё. Просто взял и прошёлся, как по парку. Никакой лишней возни.

Но есть, блядь, подводные камни, о которых орут на всех собеседованиях:

  1. Только чтение, ёбта! Это как смотреть на пирожки в витрине — видишь, нюхаешь, но взять и откусить не можешь. Нельзя во время такого цикла удалить элемент из коллекции или вставить новый. Попробуешь — получишь ConcurrentModificationException прямо в ебало, будто кирпичом. Для модификации нужен явный Iterator со своими методами remove().

  2. Индекса нет, сука! Если тебе жизненно важно знать, на каком ты сейчас шаге (пятый элемент или пятисотый), этот цикл — не твой вариант. Он просто даёт тебе элемент, а откуда он его взял — его личное дело. Для индекса старый добрый for (int i = 0; ...) в помощь.

  3. Под капотом: Для массива это компилируется в тот же унылый цикл с индексом, просто ты его не видишь. Для коллекции — в вызовы iterator(), hasNext() и next(). Так что по скорости — хуйня, разницы никакой, просто удобнее.

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