В деталях: как работает цикл 'for each' в Java?
Описание проблемы:
Я новичок в Java и столкнулся с вопросом по поводу итерации по списку. У меня есть следующий код:
List<String> someList = new ArrayList<>();
// добавляем "monkey", "donkey", "skeleton key" в someList
for (String item : someList) {
System.out.println(item);
}
Меня интересует, как выглядел бы эквивалентный цикл for
, если не использовать синтаксис for each
?
Кроме того, я заметил, что новички в Java часто сталкиваются с проблемами, когда пытаются модифицировать исходные данные с помощью нового стиля цикла foreach
. Я нашел информацию о том, что не стоит пытаться изменить переменную итерации в цикле foreach
, потому что это не изменит исходные данные. Можно ли использовать другие конструкции для решения этой проблемы?
Спасибо за любые советы!
5 ответ(ов)
Вот ответ, который не предполагает знания о Java Итераторах. Он менее точен, но полезен для обучения.
При программировании мы часто пишем код, который выглядит следующим образом:
char[] grades = ....
for(int i = 0; i < grades.length; i++) { // переменная i проходит от 0 до grades.length
System.out.print(grades[i]); // выводим grades[i]
}
Синтаксис for-each
позволяет записать этот распространённый паттерн более естественным и менее загромождённым синтаксисом.
for(char grade : grades) { // для каждого grade в grades
System.out.print(grade); // выводим этот grade
}
Кроме того, этот синтаксис также применим к объектам, таким как Lists
или Sets
, которые не поддерживают индексирование массивов, но реализуют интерфейс Iterable
в Java.
Цикл for-each в Java использует механизмы итераторов, поэтому он идентичен следующему коду:
Iterator<String> iterator = someList.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
Таким образом, можно сказать, что использование for-each позволяет писать более лаконичный и читаемый код, но за кулисами он по-прежнему работает с итераторами.
Синтаксис цикла foreach выглядит так:
for (тип объект: массив) {...}
Пример:
String[] s = {"Java", "Coffe", "Is", "Cool"};
for (String str : s /*s — это массив*/) {
System.out.println(str);
}
Вывод:
Java
Coffe
Is
Cool
ВНИМАНИЕ: Вы можете получать доступ к элементам массива с помощью цикла foreach, но вы НЕ можете их инициализировать. Для этого используйте обычный цикл for
.
ВНИМАНИЕ: Тип массива должен совпадать с типом объекта.
for (double b : s) // Неверно: double не является String
Если вы хотите изменять элементы, используйте обычный цикл for
, как в следующем примере:
for (int i = 0; i < s.length - 1 /*-1 из-за нулевого индекса*/; i++) {
if (i == 1) // 1, потому что снова указываю на нулевой индекс
s[i] = "2 is cool";
else
s[i] = "hello";
}
Теперь, если мы выведем массив s
в консоль, мы получим:
hello
2 is cool
hello
hello
Конструктция цикла "for-each" в Java позволяет итерироваться по двум типам объектов:
T[]
(массивы любого типа)java.lang.Iterable<T>
Интерфейс Iterable<T>
имеет только один метод: Iterator<T> iterator()
. Это возможно для объектов типа Collection<T>
, так как интерфейс Collection<T>
расширяет Iterable<T>
.
В Java 8 вы можете использовать лямбда-выражения и ссылки на методы для простоты работы с коллекциями. Ваш код выглядит правильно, и он демонстрирует использование метода forEach
для итерации по списку строк.
Вот как выглядит ваш пример:
List<String> messages = Arrays.asList("First", "Second", "Third");
void forTest() {
messages.forEach(System.out::println);
}
Вывод
First
Second
Third
В этом коде мы создаем список строк с помощью Arrays.asList()
, а затем используем метод forEach()
для печати каждой строки на консоль. Ссылка на метод System.out::println
является удобным способом передать логику вывода в метод forEach()
. Таким образом, у вас получается лаконичный и читаемый код.
Как работают сервлеты? Инстанцирование, сессии, общие переменные и многопоточность
Разница между StringBuilder и StringBuffer
Java 8: Преобразование List<V> в Map<K, V>
Возможные значения конфигурации hbm2ddl.auto в Hibernate и их назначение
Что такое PECS (Producer Extends Consumer Super)?