Есть коллекция и цикл foreach: List someList = new ArrayList() //add "monkey", "donkey", "skeleton key" to someList for(String item : someList) System.out.println(item) Как выглядит цикл for, эквивалентный циклу foreach выше? Как работает цикл foreach внутри? В чем отличия циклов for и foreach?
Ответ Цикл foreach - это синтаксический сахар. Внешне прежде всего отличается от for отсутствием явного счетчика. Единственное практическое различие между ними заключается в том, что в случае индексируемых объектов у вас нет доступа к индексу. Цикл foreach позволяет выполнять итерации по двум типам объектов: T[] //массивы любого типа Объекты, реализующие интерфейс Iterable. Цикл for, работающий с объектами Iterable Код из вопроса for(String item : someList) System.out.println(item) равен коду ниже for (Iterator i = someIterable.iterator() i.hasNext() ) { String item = i.next() System.out.println(item) } Этот код работает для любого объекта, реализующего интерфейс Iterable.
В цикле foreach нельзя использовать метод remove(index). Вместо этого следует использовать iterator.remove(). Пример: for (Iterator iterator = list.iterator() iterator.hasNext() ) if (iterator.next() > 10) iterator.remove()
Если писать for без использования итератора, то вот примерная реализация foreach: for(int i = 0 i < list.size() i++) System.out.println(list.get(i))
Циклы foreach и for, работающие с массивами String[] fruits = new String[] { "Orange", "Apple", "Pear", "Strawberry" } for (String fruit : fruits) { // fruit is an element of the `fruits` array. } по сути эквивалентно for (int i = 0 i < fruits.length i++) { String fruit = fruits[i] // fruit is an element of the `fruits` array. }
foreach против for - производительность При доступе к коллекции, foreach значительно быстрее, чем for. Однако при доступе к массивам - по крайней мере с массивами примитивов и оболочек - доступ через индексы(т.е. используя for) быстрее. Также при вложенных циклах foreach наблюдаются проблемы с производительностью из-за создания большого количество объектов Iterator.
В Java 8 представили потоки, которые в целом работают лучше. (хоть эта информация напрямую и не относится к вопросу, но это может быть полезно) Для работы с коллекций: someList.stream().forEach(System.out::println) Для работы с массивом: Arrays.stream(someArray).forEach(System.out::println)
Документация Oracle по foreach.
UPD: Измерение производительности на JDK9 (не стоит серьезно его оценивать, т.к. мне не кажется, что я все правильно измерил) Для замера производительности я использовал код из этого вопроса: public static void main(String[] args) { System.out.println(getTime()) } private static void testMethod() { //Код, время выполнения которого нужно узнать } /** * Метод для измерения времени выполнения метода testMethod * https:/tackoverflow.com/a/2404378/7150209 */ private static double getTime() { for (int i = 0 i < 20 i ++) { //прогрев JVM testMethod() } int count = 1000 //первоначальное кол-во повтора выполнения testMethod while(true) { long begin = System.nanoTime() for (int i = 0 i < count i ++) testMethod() long end = System.nanoTime() if ((end - begin) < 1000000000) { //Прогон тестов пока суммарное выполнения count раз count *= 100000 //testMethod`a не будет равно несколько секунд continue } return (double)(end - begin) / count } } Как работает метод getTime() - в цикле for метод с тестируемым кодом запускается count раз. Перед началом запусков засекается время, после всех запусков из конечного времени вычитается начальное - получается время запуска count раз тестового метода. После этого время делится на count - получается усредненное время одного запуска тестового метода. Если время запуска count раз тестового метода < 10 секунд, то count увеличивается, и замер происходит заново. В тестовом методе в циклах for и foreach я использовал: переменная = list.get(i)/array[i] для for и переменная = i для foreach. В лямбде я использовал Arrays.stream(array).map(l -> l+1).collect(Collectors.toList()) и list.stream().map(l -> l+1).collect(Collectors.toList()), т.е. изменение элементов коллекции и создание новой коллекции, поэтому выполнение лямбд заняло больше времени.
В таблице видно, что выполнение в лямбде заняло примерно одинаковое время для коллекций и массивов. Время выполнения кода с массивом примерно в 1.5 раза быстрее, чем с коллекцией. Время выполнения цикла for и foreach для всех одинаковое. P.S. Пример код for и foreach для коллекции(n - просто переменная): for(int i = 0 i < list.size() i++) n = list.get(i) и for(int i : list) n = i