Как работает Java «для каждого» цикла?

1499

Рассматривать:

List<String> someList = new ArrayList<String>();
// add "monkey", "donkey", "skeleton key" to someList
for (String item : someList) {
    System.out.println(item);
}

Как будет forвыглядеть эквивалентный цикл без использования для каждого синтаксиса?

Джей Р.
источник
Согласно JLS, он имеет две формы: stackoverflow.com/a/33232565/1216775
akhil_mittal

Ответы:

1176
for (Iterator<String> i = someIterable.iterator(); i.hasNext();) {
    String item = i.next();
    System.out.println(item);
}

Обратите внимание, что если вам нужно использовать i.remove();в вашем цикле или каким-либо образом получить доступ к фактическому итератору, вы не можете использовать эту for ( : )идиому, поскольку фактический итератор просто выводится.

Как отметил Денис Буэно, этот код работает для любого объекта, реализующего Iterableинтерфейс .

Кроме того, если правая часть for (:)идиомы представляет собой объект, arrayа не Iterableобъект, внутренний код использует счетчик индекса int и проверяет его array.length. Смотрите спецификацию языка Java .

nsayer
источник
14
Я обнаружил, что просто вызывая цикл while, как while (someList.hasMoreElements ()) {// do what}} - приближает меня к грации кода, которую я надеялся найти, когда искал этот вопрос.
Джеймс Т Снелл
6
Также см. Docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html, в котором объясняется цикл foreach (когда он был представлен)
PhoneixS
1
для разработчиков на android studio: import java.util.Iterator;andimport java.lang.Iterable;
dsdsdsdsd
К сожалению, java.util.Iteratorне реализует, Iterableтак что вы не можете for(String s : (Iterator<String>)foo). Я понимаю , почему это, но это раздражает.
Кристофер Шульц
499

Конструкция для каждого также действительна для массивов. например

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.
}

Итак, общее резюме:
[nsayer] Ниже приводится более длинная форма происходящего:

for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
  String item = i.next();
  System.out.println(item);
}

Обратите внимание, что если вам нужно использовать i.remove (); в вашем цикле или каким-либо образом получить доступ к фактическому итератору, вы не можете использовать идиому for (:), так как фактический итератор просто выводится.

[Денис Буэно]

Это подразумевается ответом nsayer, но стоит отметить, что синтаксис OP для (..) будет работать, когда «someList» - это что-то, что реализует java.lang.Iterable - это не обязательно должен быть список или некоторая коллекция из java.util. Таким образом, даже ваши собственные типы могут использоваться с этим синтаксисом.

Mikezx6r
источник
161

foreachЦикл , добавлен в Java 5 (также называемый «усиленный цикл»), это эквивалентно использованием java.util.Iteratorсинтаксического сахара --О для одной и тех же вещей. Поэтому при чтении каждого элемента по порядку и по порядку foreachвсегда следует выбирать a через итератор, так как это более удобно и кратко.

для каждого

for(int i : intList) {
   System.out.println("An element in the list: " + i);
}

Итератор

Iterator<Integer> intItr = intList.iterator();
while(intItr.hasNext()) {
   System.out.println("An element in the list: " + intItr.next());
}

Есть ситуации, когда вы должны использовать Iteratorнапрямую. Например, попытка удалить элемент при использовании foreachcan (will?) Приведет к ConcurrentModificationException.

foreachпротив for: основные различия

Единственное практическое различие между forи foreachзаключается в том, что в случае индексируемых объектов у вас нет доступа к индексу. Пример, когда forтребуется базовый цикл:

for(int i = 0; i < array.length; i++) {
   if(i < 5) {
      // Do something special
   }  else {
      // Do other stuff
   }
}

Хотя вы можете вручную создать отдельный индекс Инт-переменный foreach,

int idx = -1;
for(int i : intArray) {
   idx++;
   ...
}

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

foreachпротив for: производительность

При доступе к коллекции, foreachэто значительно быстрее , чем основной forдоступ к массиву передачи контура в. Однако при доступе к массивам - по крайней мере с массивами примитивов и оболочек - доступ через индексы значительно быстрее.

Синхронизация разницы между итератором и доступом к индексу для примитивных int-массивов

Индексы 23- 40 процентов быстрее , чем итераторы при доступе intили Integerмассивов. Ниже приведен вывод из класса тестирования в нижней части этого поста, который суммирует числа в массиве primitive-int из 100 элементов (A - итератор, B - индекс):

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 358,597,622 nanoseconds
Test B: 269,167,681 nanoseconds
B faster by 89,429,941 nanoseconds (24.438799231635727% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 377,461,823 nanoseconds
Test B: 278,694,271 nanoseconds
B faster by 98,767,552 nanoseconds (25.666236154695838% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 288,953,495 nanoseconds
Test B: 207,050,523 nanoseconds
B faster by 81,902,972 nanoseconds (27.844689860906513% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,373,765 nanoseconds
Test B: 283,813,875 nanoseconds
B faster by 91,559,890 nanoseconds (23.891659337194227% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,790,818 nanoseconds
Test B: 220,770,915 nanoseconds
B faster by 155,019,903 nanoseconds (40.75164734599769% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 326,373,762 nanoseconds
Test B: 202,555,566 nanoseconds
B faster by 123,818,196 nanoseconds (37.437545972215744% faster)

Я также выполнил это для Integerмассива, и индексы по-прежнему явный победитель, но только на 18-25% быстрее.

Для коллекций итераторы работают быстрее, чем индексы

Для ListOF Integers, однако, итераторы явным победителем. Просто измените массив int в классе теста на:

List<Integer> intList = Arrays.asList(new Integer[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100});

И внесите необходимые изменения в функцию test ( int[]to List<Integer>, lengthto size()и т. Д.):

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,429,929,976 nanoseconds
Test B: 5,262,782,488 nanoseconds
A faster by 1,832,852,512 nanoseconds (34.326681820485675% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,907,391,427 nanoseconds
Test B: 3,957,718,459 nanoseconds
A faster by 1,050,327,032 nanoseconds (26.038700083921256% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,566,004,688 nanoseconds
Test B: 4,221,746,521 nanoseconds
A faster by 1,655,741,833 nanoseconds (38.71935684115413% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,770,945,276 nanoseconds
Test B: 3,829,077,158 nanoseconds
A faster by 1,058,131,882 nanoseconds (27.134122749113843% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,467,474,055 nanoseconds
Test B: 5,183,149,104 nanoseconds
A faster by 1,715,675,049 nanoseconds (32.60101667104192% faster)

[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,439,983,933 nanoseconds
Test B: 3,509,530,312 nanoseconds
A faster by 69,546,379 nanoseconds (1.4816434912159906% faster)

[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,451,101,466 nanoseconds
Test B: 5,057,979,210 nanoseconds
A faster by 1,606,877,744 nanoseconds (31.269164666060377% faster)

В одном тесте они почти эквивалентны, но с коллекциями побеждает итератор.

* Этот пост основан на двух ответах, которые я написал о переполнении стека:

Еще немного информации: что является более эффективным: цикл для каждого или итератор?

Полный класс тестирования

Я создал этот класс «сравнивать время, которое требуется, чтобы делать любые две вещи» после прочтения этого вопроса о переполнении стека:

import  java.text.NumberFormat;
import  java.util.Locale;

/**
   &lt;P&gt;{@code java TimeIteratorVsIndexIntArray 1000000}&lt;/P&gt;

   @see  &lt;CODE&gt;&lt;A HREF=&quot;/programming/180158/how-do-i-time-a-methods-execution-in-java&quot;&gt;/programming/180158/how-do-i-time-a-methods-execution-in-java&lt;/A&gt;&lt;/CODE&gt;
 **/
public class TimeIteratorVsIndexIntArray {

    public static final NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);

    public static final void main(String[] tryCount_inParamIdx0) {
        int testCount;

        // Get try-count from a command-line parameter
        try {
           testCount = Integer.parseInt(tryCount_inParamIdx0[0]);
        }
        catch(ArrayIndexOutOfBoundsException | NumberFormatException x) {
           throw  new IllegalArgumentException("Missing or invalid command line parameter: The number of testCount for each test. " + x);
        }

        //Test proper...START
        int[] intArray = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100};

        long lStart = System.nanoTime();
        for(int i = 0; i < testCount; i++) {
           testIterator(intArray);
        }

        long lADuration = outputGetNanoDuration("A", lStart);

        lStart = System.nanoTime();
        for(int i = 0; i < testCount; i++) {
           testFor(intArray);
        }

        long lBDuration = outputGetNanoDuration("B", lStart);

        outputGetABTestNanoDifference(lADuration, lBDuration, "A", "B");
    }

    private static final void testIterator(int[] int_array) {
       int total = 0;
       for(int i = 0; i < int_array.length; i++) {
          total += int_array[i];
       }
    }

    private static final void testFor(int[] int_array) {
       int total = 0;
       for(int i : int_array) {
          total += i;
       }
    }
    //Test proper...END

    //Timer testing utilities...START
    public static final long outputGetNanoDuration(String s_testName, long l_nanoStart) {
        long lDuration = System.nanoTime() - l_nanoStart;
        System.out.println("Test " + s_testName + ": " + nf.format(lDuration) + " nanoseconds");
        return  lDuration;
    }

    public static final long outputGetABTestNanoDifference(long l_aDuration, long l_bDuration, String s_aTestName, String s_bTestName) {
        long lDiff = -1;
        double dPct = -1.0;
        String sFaster = null;
        if(l_aDuration > l_bDuration) {
            lDiff = l_aDuration - l_bDuration;
            dPct = 100.00 - (l_bDuration * 100.0 / l_aDuration + 0.5);
            sFaster = "B";
        }
        else {
            lDiff = l_bDuration - l_aDuration;
            dPct = 100.00 - (l_aDuration * 100.0 / l_bDuration + 0.5);
            sFaster = "A";
        }
        System.out.println(sFaster + " faster by " + nf.format(lDiff) + " nanoseconds (" + dPct + "% faster)");
        return  lDiff;
   }

   //Timer testing utilities...END

}
aliteralmind
источник
4
Этот ответ теперь является постом в блоге и был создан из двух связанных ответов, которые я написал: здесь и здесь . Он также включает в себя полезный класс для сравнения скорости двух функций (внизу).
aliteralmind
1
Здесь только один небольшой комментарий, вы не должны категорически утверждать, что синтаксис for (:) всегда лучше для доступа к коллекциям; Если вы используете список массивов, цикл for (:) будет примерно в 2 раза медленнее, чем при использовании for (int i = 0, len = arrayList.size (); i <len; i ++). Я думаю, что вы упомянули об этом в ссылке [link] ( stackoverflow.com/questions/2113216/… ) в любом случае, но важно подчеркнуть это ...
Лев
@ Leo Это хороший момент. ArrayList - это Collection, но он поддерживается массивом, поэтому нормальное значение for лучше для него.
aliteralmind
Я думаю, что for(int value : int_array) {/* loop content */}это самый медленный в вашем тесте, потому что он синтаксически эквивалентен for(int i = 0; i < int_array.length; i++) {int value = int_array[i]; /* loop content */}, а это не то, что ваш тест сравнивает.
daiscog
(кстати, я не говорю, что ваш тест недействителен, но, возможно, стоит отметить причины различий, чтобы люди могли выбрать то, что подходит для их конкретного сценария. Если они делают int value = int_array[i];в начале их для цикл, тогда они могут также использовать foreach. Если по какой-то причине им тоже не нужен доступ к индексу. Короче, все зависит от контекста.)
daiscog
129

Вот ответ, который не предполагает знания Java Iterators. Это менее точно, но это полезно для образования.

При программировании мы часто пишем код, который выглядит следующим образом:

char[] grades = ....
for(int i = 0; i < grades.length; i++) {   // for i goes from 0 to grades.length
    System.out.print(grades[i]);           // Print grades[i]
}

Синтаксис foreach позволяет писать этот общий шаблон более естественным и менее синтаксически шумным способом.

for(char grade : grades) {   // foreach grade in grades
    System.out.print(grade); // print that grade
}

Кроме того, этот синтаксис действителен для таких объектов, как списки или наборы, которые не поддерживают индексацию массива, но которые реализуют интерфейс Java Iterable.

MRocklin
источник
40

Цикл for-each в Java использует базовый механизм итератора. Так что это идентично следующему:

Iterator<String> iterator = someList.iterator();

while (iterator.hasNext()) {
  String item = iterator.next();
  System.out.println(item);
}
toluju
источник
25

В функциях Java 8 вы можете использовать это:

List<String> messages = Arrays.asList("First", "Second", "Third");

void forTest(){
    messages.forEach(System.out::println);
}

Вывод

First
Second
Third
Jrovalle
источник
7
эта случайная информация даже не дает ответа на этот вопрос
Тим
25

Это подразумевается ответом nsayer, но стоит отметить, что синтаксис OP для (..) будет работать, когда «someList» - это что- то, что реализует java.lang.Iterable - это не обязательно должен быть список или некоторая коллекция из java.util. Таким образом, даже ваши собственные типы могут использоваться с этим синтаксисом.

EfForEffort
источник
1
Право fd - внутренний код, когда правая часть идиомы for (:) использует int и array.length вместо выборки Iterator. forums.sun.com/thread.jspa?messageID=2743233
nsayer
24

Как определено в JLS, цикл for-each может иметь две формы:

  1. Если тип Выражения является подтипом, Iterableтогда перевод выглядит так:

    List<String> someList = new ArrayList<String>();
    someList.add("Apple");
    someList.add("Ball");
    for (String item : someList) {
        System.out.println(item);
    }
    
    // IS TRANSLATED TO:
    
    for(Iterator<String> stringIterator = someList.iterator(); stringIterator.hasNext(); ) {
        String item = stringIterator.next();
        System.out.println(item);
    }
  2. Если выражение обязательно имеет тип массива, T[]тогда:

    String[] someArray = new String[2];
    someArray[0] = "Apple";
    someArray[1] = "Ball";
    
    for(String item2 : someArray) {
        System.out.println(item2);
    }
    
    // IS TRANSLATED TO:
    for (int i = 0; i < someArray.length; i++) {
        String item2 = someArray[i];
        System.out.println(item2);
    }

Java 8 представила потоки, которые в целом работают лучше. Мы можем использовать их как:

someList.stream().forEach(System.out::println);
Arrays.stream(someArray).forEach(System.out::println);
akhil_mittal
источник
2
Самый актуальный и точный ответ. Зачарованный для имеет два перевода действительно.
Зариал
23

Синтаксис цикла foreach:

for (type obj:array) {...}

Пример:

String[] s = {"Java", "Coffe", "Is", "Cool"};
for (String str:s /*s is the array*/) {
    System.out.println(str);
}

Вывод:

Java
Coffe
Is
Cool

ВНИМАНИЕ: Вы можете получить доступ к элементам массива с помощью цикла foreach, но НЕ можете их инициализировать. Используйте оригинальный forцикл для этого.

ВНИМАНИЕ: Вы должны сопоставить тип массива с другим объектом.

for (double b:s) // Invalid-double is not String

Если вы хотите редактировать элементы, используйте оригинальный forцикл следующим образом:

for (int i = 0; i < s.length-1 /*-1 because of the 0 index */; i++) {
    if (i==1) //1 because once again I say the 0 index
        s[i]="2 is cool";
    else
        s[i] = "hello";
}

Теперь, если мы сбросим s в консоль, мы получим:

hello
2 is cool
hello
hello
PrivateName
источник
21

Конструкция цикла Java «для каждого» позволяет выполнять итерации по двум типам объектов:

  • T[] (массивы любого типа)
  • java.lang.Iterable<T>

Iterable<T>Интерфейс имеет только один метод: Iterator<T> iterator(). Это работает с объектами типа, Collection<T>потому что Collection<T>интерфейс расширяется Iterable<T>.

Райан Делукки
источник
16

Концепция цикла foreach, упомянутая в Википедии, освещена ниже:

Однако, в отличие от других конструкций цикла for, циклы foreach обычно не содержат явного счетчика : они, по сути, говорят «делай это со всем в этом наборе», а не «делай это x раз». Это позволяет избежать потенциальных ошибок, связанных с ошибками, и упрощает чтение кода.

Таким образом, концепция цикла foreach описывает, что цикл не использует какой-либо явный счетчик, что означает, что нет необходимости использовать индексы для перемещения по списку, таким образом, он спасает пользователя от ошибки «один на один». Чтобы описать общую концепцию этой ошибки, давайте возьмем пример цикла для перемещения по списку с использованием индексов.

// In this loop it is assumed that the list starts with index 0
for(int i=0; i<list.length; i++){

}

Но предположим, что если список начинается с индекса 1, то этот цикл будет генерировать исключение, так как он не найдет элемент с индексом 0, и эта ошибка называется ошибкой «один за другим». Поэтому, чтобы избежать этой ошибки, используется концепция цикла foreach. Могут быть и другие преимущества, но это то, что я считаю основной концепцией и преимуществом использования цикла foreach.

oneConsciousness
источник
13

В Java 8 они представили forEach. Используя этот список, карты могут быть зациклены.

Цикл Список, используя для каждого

List<String> someList = new ArrayList<String>();
someList.add("A");
someList.add("B");
someList.add("C");

someList.forEach(listItem -> System.out.println(listItem))

или

someList.forEach(listItem-> {
     System.out.println(listItem); 
});

Зациклить карту, используя для каждого

Map<String, String> mapList = new HashMap<>();
    mapList.put("Key1", "Value1");
    mapList.put("Key2", "Value2");
    mapList.put("Key3", "Value3");

mapList.forEach((key,value)->System.out.println("Key: " + key + " Value : " + value));

или

mapList.forEach((key,value)->{
    System.out.println("Key : " + key + " Value : " + value);
});
vivekkurien
источник
12
for (Iterator<String> itr = someList.iterator(); itr.hasNext(); ) {
   String item = itr.next();
   System.out.println(item);
}
Роджер Линдсё
источник
11

Используя более старые версии Java, в том числе Java 7вы можете использовать foreachцикл следующим образом.

List<String> items = new ArrayList<>();
        items.add("A");
        items.add("B");
        items.add("C");
        items.add("D");
        items.add("E");

        for(String item : items){
            System.out.println(item);
        }

Ниже приводится самый последний способ использования foreachцикла вJava 8

(зациклить список с помощью forEachлямбда-выражения или ссылки на метод)

//lambda
    //Output : A,B,C,D,E
    items.forEach(item->System.out.println(item));


//method reference
    //Output : A,B,C,D,E
    items.forEach(System.out::println);

Для получения дополнительной информации перейдите по этой ссылке.

https://www.mkyong.com/java8/java-8-foreach-examples/

Дулит Де Коста
источник
10

Вот эквивалентное выражение.

for(Iterator<String> sit = someList.iterator(); sit.hasNext(); ) {
    System.out.println(sit.next());
}
моток
источник
10

Также обратите внимание, что использование метода «foreach» в исходном вопросе имеет некоторые ограничения, такие как невозможность удаления элементов из списка во время итерации.

Новый цикл for проще для чтения и устраняет необходимость в отдельном итераторе, но он действительно применим только для проходов только для чтения.

billjamesdev
источник
1
В этих случаях использование removeIfможет быть правильным инструментом
ncmathsadist
9

Альтернатива forEach для того, чтобы избежать вашего «для каждого»:

List<String> someList = new ArrayList<String>();

Вариант 1 (простой):

someList.stream().forEach(listItem -> {
    System.out.println(listItem);
});

Вариант 2 (параллельное выполнение (быстрее)):

someList.parallelStream().forEach(listItem -> {
    System.out.println(listItem);
});
Александр Дробышевский
источник
2
Стоит упомянуть, что он добавлен в Java 1.8
TheLibrarian
Мы не можем быть на 100% уверены, что используется одна и та же нить. Мне нравится использовать for(форму, если я хочу убедиться, что используется одна и та же тема. Мне нравится использовать потоковую форму, если я хочу разрешить многопоточное выполнение.
Грим
8

Это добавляет красоты вашему коду, удаляя все основные циклы беспорядка. Это дает чистый взгляд на ваш код, приведенный ниже.

Нормальный forцикл:

void cancelAll(Collection<TimerTask> list) {
    for (Iterator<TimerTask> i = list.iterator(); i.hasNext();)
         i.next().cancel();
}

Используя для каждого:

void cancelAll(Collection<TimerTask> list) {
    for (TimerTask t : list)
        t.cancel();
}

for-each является конструкцией над коллекцией, которая реализует Iterator . Помните, что ваша коллекция должна реализовывать Iterator ; в противном случае вы не можете использовать его для каждого.

Следующая строка читается как « для каждого TimerTask t в списке ».

for (TimerTask t : list)

Существует меньше шансов на ошибки в случае для каждого. Вам не нужно беспокоиться об инициализации итератора или инициализации счетчика цикла и его завершении (там, где есть место для ошибок).

Manohar
источник
8

До Java 8 вам необходимо использовать следующее:

Iterator<String> iterator = someList.iterator();

while (iterator.hasNext()) {
    String item = iterator.next();
    System.out.println(item);
}

Однако с появлением Streams в Java 8 вы можете делать то же самое с гораздо меньшим синтаксисом. Например, для вашего someListвы можете сделать:

someList.stream().forEach(System.out::println);

Вы можете найти больше о потоках здесь .

stackFan
источник
The foreach loop, added in Java 5 (also called the "enhanced for loop"), is equivalent to using a java.util.Iterator
Alex78191
7

Это будет выглядеть примерно так. Очень грубый

for (Iterator<String> i = someList.iterator(); i.hasNext(); )
        System.out.println(i.next());

В документации Sun есть хорошая рецензия для каждого из них .

Пит
источник
6

Как сказано во многих хороших ответах, объект должен реализовывать цикл, Iterable interfaceесли он хочет использовать for-eachцикл.

Я опубликую простой пример и попытаюсь по-другому объяснить, как работает for-eachцикл.

for-eachПример цикла:

public class ForEachTest {

    public static void main(String[] args) {

        List<String> list = new ArrayList<String>();
        list.add("111");
        list.add("222");

        for (String str : list) {
            System.out.println(str);
        }
    }
}

Затем, если мы используем javapдля декомпиляции этого класса, мы получим этот пример байт-кода:

public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #16                 // class java/util/ArrayList
         3: dup
         4: invokespecial #18                 // Method java/util/ArrayList."<init>":()V
         7: astore_1
         8: aload_1
         9: ldc           #19                 // String 111
        11: invokeinterface #21,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        16: pop
        17: aload_1
        18: ldc           #27                 // String 222
        20: invokeinterface #21,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        25: pop
        26: aload_1
        27: invokeinterface #29,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;

Как мы видим из последней строки примера, компилятор автоматически преобразует использование for-eachключевого слова в использование во время Iteratorкомпиляции. Это может объяснить, почему объект, который не реализует Iterable interface, будет выдавать, Exceptionкогда он пытается использовать for-eachцикл.

L Joey
источник
6

Java для каждого цикла ( так называемый цикл усиления) представляет собой упрощенную версию для цикла. Преимущество состоит в том, что меньше кода для написания и меньше переменных для управления. Недостатком является то, что у вас нет контроля над значением шага и нет доступа к индексу цикла внутри тела цикла.

Их лучше всего использовать, когда значение шага является простым приращением 1 и когда вам нужен только доступ к текущему элементу цикла. Например, если вам нужно перебрать каждый элемент в массиве или коллекции, не заглядывая вперед или позади текущего элемента.

Здесь нет инициализации цикла, нет логического условия, а значение шага неявно и представляет собой простое приращение. Вот почему они считаются намного проще, чем обычные для циклов.

Усовершенствованные циклы for следуют этому порядку выполнения:

1) тело петли

2) повторять с шага 1 до тех пор, пока не будет пройден весь массив или коллекция

Пример - Целочисленный Массив

int [] intArray = {1, 3, 5, 7, 9};
for(int currentValue : intArray) {
  System.out.println(currentValue);
}

Переменная currentValue содержит текущее значение, зацикленное в массиве intArray. Обратите внимание, что нет явного значения шага - оно всегда увеличивается на 1.

Можно предположить, что двоеточие означает «в». Таким образом, расширенные состояния объявления цикла: перебирайте intArray и сохраняйте текущее значение массива int в переменной currentValue.

Вывод:

1
3
5
7
9

Пример - String Array

Мы можем использовать цикл for-each для итерации по массиву строк. Объявление цикла гласит: зациклите массив String myStrings и сохраните текущее значение String в переменной currentString.

String [] myStrings  = {
  "alpha",
  "beta",
  "gamma",
  "delta"
};

for(String currentString : myStrings) {
  System.out.println(currentString);
}

Вывод:

alpha
beta
gamma
delta

Пример - Список

Усовершенствованный цикл for также можно использовать для перебора java.util.List следующим образом:

List<String> myList = new ArrayList<String>();
myList.add("alpha");
myList.add("beta");
myList.add("gamma");
myList.add("delta");

for(String currentItem : myList) {
  System.out.println(currentItem);
}

Объявление цикла сообщает: переберите список строк myList и сохраните текущее значение списка в переменной currentItem.

Вывод:

alpha
beta
gamma
delta

Пример - Установить

Усовершенствованный цикл for также можно использовать для перебора java.util.Set следующим образом:

Set<String> mySet = new HashSet<String>();
mySet.add("alpha");
mySet.add("alpha");
mySet.add("beta");
mySet.add("gamma");
mySet.add("gamma");
mySet.add("delta");

for(String currentItem : mySet) {
  System.out.println(currentItem);
}

Объявление цикла гласит: зациклите набор строк mySet и сохраните текущее значение Set в переменной currentItem. Обратите внимание, что, поскольку это Set, повторяющиеся значения String не сохраняются.

Вывод:

alpha
delta
beta
gamma

Источник: циклы в Java - полное руководство

gomisha
источник
4
public static Boolean Add_Tag(int totalsize)
{ List<String> fullst = new ArrayList<String>();
            for(int k=0;k<totalsize;k++)
            {
              fullst.addAll();
            }
}
Сантош Раджкумар
источник
3

Идиома Java for-each может применяться только к массивам или объектам типа * Iterable . Эта идиома неявная, поскольку она действительно поддерживается итератором. Итератор программируется программистом и часто использует целочисленный индекс или узел (в зависимости от структуры данных) для отслеживания своей позиции. На бумаге он медленнее обычного цикла for, наименьший для «линейных» структур, таких как массивы и списки, но он обеспечивает большую абстракцию.

TheArchon
источник
-1: это менее читабельно (как правило): даже ваш собственный пример (первый) неверен, так как пропускает первый элемент в массиве.
Ондрей Скопек
2

Это выглядит сумасшедшим, но эй, это работает

List<String> someList = new ArrayList<>(); //has content
someList.forEach(System.out::println);

Это работает. магия

Рей Браун
источник
1
Для этого требуется Java
1.8+
2
даже отдаленно не отвечает на вопрос
Тим
2

Как правильно утверждают многие другие ответы, for each loopсинтаксический сахар - это просто тот же старый, for loopи компилятор переводит его в тот же старый цикл for.

javac (open jdk) имеет переключатель -XD-printflat, который генерирует файл java со всеми удаленными синтаксическими сахарами. полная команда выглядит следующим образом

javac -XD-printflat -d src/ MyFile.java

//-d is used to specify the directory for output java file

Так что давайте удалим синтаксический сахар

Чтобы ответить на этот вопрос, я создал файл и написал две версии for each, одну с, arrayа другую с list. мой javaфайл выглядел так

import java.util.*;
public class Temp{

    private static void forEachArray(){
        int[] arr = new int[]{1,2,3,4,5};
        for(int i: arr){
            System.out.print(i);
        }
    }

    private static void forEachList(){
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        for(Integer i: list){
            System.out.print(i);
        }
    }
}

Когда я compiledэтот файл с вышеупомянутым переключателем, я получил следующий вывод.

import java.util.*;

public class Temp {

    public Temp() {
        super();
    }

    private static void forEachArray() {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        for (/*synthetic*/ int[] arr$ = arr, len$ = arr$.length, i$ = 0; i$ < len$; ++i$) {
            int i = arr$[i$];
            {
                System.out.print(i);
            }
        }
    }

    private static void forEachList() {
        List list = Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4), Integer.valueOf(5)});
        for (/*synthetic*/ Iterator i$ = list.iterator(); i$.hasNext(); ) {
            Integer i = (Integer)i$.next();
            {
                System.out.print(i);
            }
        }
    }
}

Вы можете видеть, что наряду с другим синтаксическим сахаром (Autoboxing) для каждого цикла были изменены простые циклы.

mightyWOZ
источник
-2
List<Item> Items = obj.getItems();
for(Item item:Items)
             {
                System.out.println(item); 
             }

Перебирает все объекты в таблице Items.

Шубраншу
источник
1
Пользователь не запрашивал синтаксис
pradipgarala