Есть коллекция и цикл foreach
:
List<String> someList = new ArrayList<String>();
//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<E> i = someIterable.iterator(); i.hasNext();) {
String item = i.next();
System.out.println(item);
}
Этот код работает для любого объекта, реализующего интерфейс Iterable
.
В цикле foreach
нельзя использовать метод remove(index)
. Вместо этого следует использовать iterator.remove()
. Пример:
for (Iterator<Integer> 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
.
(не стоит серьезно его оценивать, т.к. мне не кажется, что я все правильно измерил)
Для замера производительности я использовал код из этого вопроса:
public static void main(String[] args) {
System.out.println(getTime());
}
private static void testMethod() {
//Код, время выполнения которого нужно узнать
}
/**
* Метод для измерения времени выполнения метода testMethod
* https://stackoverflow.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;
Виртуальный выделенный сервер (VDS) становится отличным выбором
Написал метод, который по-идее должен считывать из текстового файла по расположению (path) определенное количество символов (length), со смещением...
[Petr, Alexandr, Ivan, Dmitriy] вот что я получил в консольПочему вышли значения таким образом, а не по порядку как в ArrayList например?
Необходимо отследить перемещение одной белой точки на черном фонеИспользую OpenCV и класс CameraPreview на основе SurfaceView