Кратко
for-eachэто сокращенная форма циклаforдля перебора всех элементов подряд:for (Тип переменная : источник).- Слова
foreachв Java нет: ключевое слово тут обычныйfor, а роль разделителя играет двоеточие. - Работает с массивами и с любым объектом, класс которого реализует
java.lang.Iterable, то есть со всеми стандартными коллекциями. - Индекса у него нет: переменная на каждом шаге получает сам элемент, а не его номер.
- Поэтому через
for-eachне пройти список с конца, не заменить элементы массива, не узнать позицию найденного элемента и не удалить элемент коллекции по ходу обхода. - Когда индекс не нужен, брать стоит именно
for-each: он короче, и в нем нельзя ошибиться с границами.
Что такое foreach в Java?
For-each это разновидность цикла for, которая используется, когда нужно обработать все элементы массива или коллекции. “For each” с английского так и переводится: “для каждого”. Собственно, само словосочетание foreach в этом цикле не используется. Его синтаксис следующий:for (type itVar : array)
{
Блок операторов;
}
Здесь type это тип итерационной переменной (совпадает с типом данных в массиве!), itVar ее имя, array сам массив (тут также может быть другая структура данных, какая-нибудь коллекция, например, ArrayList), то есть объект, по которому выполняется цикл. Как вы видите, счетчик в такой конструкции не применяется, итерационная переменная перебирает элементы массива или коллекции, а не значения индекса.
При выполнении такого цикла, итерационной переменной последовательно присваивается значение каждого элемента массива или коллекции, после чего выполняется указанный блок операторов (или оператор).
Помимо цикла for-each в Java также есть метод forEach(). О нем можно почитать, например, в статье “Хватит писать циклы! Топ-10 лучших методов для работы с коллекциями в Java 8” |
for (int i=0; i<array.length; i++)
{
Блок операторов;
}Пример использования Java foreach
Создадим массив из оценок ученика. Затем с помощью for-each распечатаем все оценки, выведем среднюю оценку и найдем максимальную из них.public class ForEachTest {
//метод, который распечатывает все оценки
public static void printAllGrades(int[] grades) {
System.out.print("|");
for (int num : grades) {
System.out.print(num + "|");
}
System.out.println();
}
//метод, в котором выводится средняя оценка
public static double midGrade(int[] numbers) {
int grade = 0;
for (int num : numbers) {
grade = num + grade;
}
return ((double) grade / numbers.length);
}
//метод в котором вычисляется лучшая (максимальная) оценка
public static int bestGrade(int[] numbers) {
int maxGrade = numbers[0];
for (int num : numbers) {
if (num > maxGrade) {
maxGrade = num;
}
}
return maxGrade;
}
public static void main(String[] args) {
//массив оценок
int[] grades = {5, 10, 7, 8, 9, 9, 10, 12};
int highest_marks = bestGrade(grades);
System.out.print("All the grades: ");
printAllGrades(grades);
System.out.println("The highest grade is " + highest_marks);
System.out.println("The average grade is " + midGrade(grades));
}
}
Вывод программы:
All the grades: |5|10|7|8|9|9|10|12|
The highest grade is 12
The average grade is 8.75
А теперь давайте посмотрим, как бы выглядел метод распечатывания всех оценок, выполненный с помощью обычного цикла for:
public static void printAllGrades(int[] grades) {
System.out.print("|");
for (int i = 0; i < grades.length; i++) {
System.out.print(grades[i] + "|");
}
System.out.println();
}
Если вызвать этот метод из метода main, мы получим результат:
All the grades: |5|10|7|8|9|9|10|12|Пример использования цикла for-each с коллекциями
Создадим коллекцию из имен и выведем все имена на экран.List<String> names = new ArrayList<>();
names.add("Snoopy");
names.add("Charlie");
names.add("Linus");
names.add("Shroeder");
names.add("Woodstock");
for(String name : names){
System.out.println(name);
}С Java 10 тип итерационной переменной можно не указывать явно: for (var name : names). Компилятор выведет его сам, на поведение цикла это никак не влияет.Ограничения цикла for-each
Компактная форма for-each считается более читаемой, чем for, и правилом хорошего тона считается использовать именно for-each там, где это можно сделать. Однако for-each это менее универсальная конструкция, чем обычный for. Приведем несколько простых случаев, где воспользоваться for-each не получится вовсе или получится, но с трудом.Если вы хотите пройти по циклу с конца в начало. То есть прямого for-each аналога следующему коду нет:
for (int i = array.length - 1; i >= 0; i--) { System.out.println(array[i]); }For-each не подходит, если вы хотите внести изменения в массив. Например, не получится организовать сортировку массива, не меняя его элементы местами. Или вот, в следующем коде изменится не элемент массива, а только итерационная переменная:
for (int itVar : array) { itVar++; }Если вы ищете элемент в массиве и вам нужно вернуть (или передать дальше) индекс искомого элемента, лучше воспользоваться обычным циклом for.
for-each и обычный for: что выбрать
Соберем все различия в одну таблицу, чтобы было видно, когда какой цикл брать.| Задача | for-each | обычный for |
|---|---|---|
| Узнать индекс элемента | нельзя, переменная хранит сам элемент | можно, индекс это и есть счетчик |
| Пройти с конца в начало | нельзя | можно |
| Заменить элементы массива | нельзя, меняется только итерационная переменная | можно, через array[i] = ... |
| Удалить элемент коллекции по ходу обхода | нельзя, вылетит ConcurrentModificationException | можно, но придется следить за сдвигом индексов |
| По чему можно пройти | массивы и все, что реализует Iterable | все, к чему есть доступ по индексу или счетчику |
| Объем кода | короче, границы задавать не нужно | длиннее, зато полный контроль |
Вопросы и ответы
Чем for-each отличается от обычного цикла for?
Вfor-each нет счетчика и индекса: переменная на каждом шаге получает сам элемент. Обычный for работает с номером позиции, поэтому умеет идти с конца, менять элементы массива и возвращать индекс найденного элемента.По чему можно пройти циклом for-each?
По массиву любого типа и по любому объекту, класс которого реализует интерфейсjava.lang.Iterable. Под это условие подходят все стандартные коллекции: ArrayList, LinkedList, HashSet и остальные.Почему в for-each нельзя изменить элементы массива?
Итерационная переменная это копия значения элемента или копия ссылки на него, а не сам элемент. Присваивание внутри цикла меняет только переменную, массив остается прежним. Чтобы записать новое значение, нужен индекс, то есть обычныйfor.Можно ли удалять элементы коллекции внутри for-each?
Нет. При первой же попытке удалить что-то из коллекции прямо в цикле вылетитConcurrentModificationException. Удалять нужно либо через явный Iterator и его метод remove(), либо методом removeIf().
Как пройти циклом for-each по Map?
Напрямую нельзя:Map не реализует Iterable. Перебирают либо ключи через keySet(), либо значения через values(), либо пары целиком через entrySet(), и тогда переменная цикла будет типа Map.Entry.Можно ли в for-each не писать тип переменной?
Да, начиная с Java 10 вместо типа пишутvar, и компилятор выведет тип сам: for (var num : grades). На поведение цикла это не влияет, это только сокращение записи.Полезное видео о for-each, подготовленное учеником JavaRush
Циклы в курсе JavaRushНа JavaRush к использованию циклов на практике приступают на 4 уровне квеста Java Syntax. Там им посвящено несколько лекций, а также множество задач разного уровня для закрепления навыков работы с ними. Вообще, никуда вы от них не денетесь, циклы это одна из важнейших конструкций в программировании. |
Подробнее о for-each и циклах:
- For и For-Each Loop: сказ о том, как я итерировался, итерировался, да не выитерировался, хорошая подробная статья о циклах for и for-each в Java. Рассчитана на подготовленного читателя (примерно от 10 уровня JavaRush и выше).
- Оператор While. Статья посвящена самому простому циклу
while, с которого начинается знакомство с циклами на JavaRush. - Хватит писать циклы! Топ-10 лучших методов для работы с коллекциями в Java 8. Из этой статьи студент JavaRush, который уже прошел половину курса или больше, узнает много интересного о работе с коллекциями.
- Коллекции в Java: Java Collections Framework. Обзор коллекций, по которым чаще всего и ходит for-each: списки, множества, очереди и Map.