Як працює Java 'для кожного циклу?


1498

Поміркуйте:

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

Відповіді:


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

Зауважте, що якщо вам потрібно використовувати i.remove();у своєму циклі або якимсь чином отримати доступ до фактичного ітератора, ви не можете використовувати for ( : )ідіому, оскільки власне ітератор виводиться просто.

Як зазначив Денис Буено, цей код працює для будь-якого об’єкта, що реалізує Iterableінтерфейс .

Крім того, якщо права частина for (:)ідіоми - це, arrayа не Iterableоб'єкт, внутрішній код використовує лічильник int index і array.lengthзамість нього перевіряє . Див . Специфікацію мови Java .


14
Я знайшов просто виклик циклу while на зразок while (someList.hasMoreElements ()) {// робити щось}} - наближає мене до грації кодування, яку я сподівався знайти, коли шукав це питання.
Джеймс Т Снелл

6
Також дивіться docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html, які пояснюють цикл foreach (коли він був введений)
PhoneixS

1
для розробників андроїд-студії: import java.util.Iterator;іimport 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, але варто відзначити, що синтаксис ОП для (..) буде працювати, коли "someList" - це все, що реалізує java.lang.Iterable - це не повинно бути списком чи деякою колекцією з java.util. Тому навіть ваші власні типи можуть використовуватися з цим синтаксисом.


161

foreachЦикл , доданий в Java 5 (також званий «посилений цикл»), це еквівалентно використанням java.util.Iteratorсинтаксичного цукру --О для однієї і тих же речей. Тому, читаючи кожен елемент, один за одним і в порядку, foreachзавжди слід вибирати ітератор, оскільки це зручніше і стисліше.

для кожного

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?) Призводить до появи a ConcurrentModificationException.

foreachvs 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цикл - це просто стандартний і очікуваний формат для цього випадку використання.

foreachvs for.: Продуктивність

При доступі до колекції, foreachце значно швидше , ніж основний forдоступ до масиву передачі контуру в. Однак при доступі до масивів - принаймні, з примітивними та обгортковими масивами - доступ через індекси значно різко.

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

Індекси 23- 40 відсотків швидше , ніж ітератори при доступі intабо Integerмасивів. Ось вихід із класу тестування внизу цієї публікації, який підсумовує числа в 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});

І внесіть необхідні зміни до тестової функції ( int[]до List<Integer>, lengthдо 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

}

4
Ця відповідь зараз є дописом у блозі та створена з двох відповідей, які я написав: тут і тут . Він також включає загально корисний клас для порівняння швидкості двох функцій (внизу).
aliteralmind

1
Лише один незначний коментар тут не повинен категорично заявляти, що для (:) синтаксис завжди кращий для доступу до колекцій; якщо ви використовуєте список масивів, цикл for (:) буде приблизно в 2 рази повільніше, ніж використання для (int i = 0, len = arrayList.size (); i <len; i ++). Думаю, ви згадали, що у [посиланні] ( stackoverflow.com/questions/2113216/… ) посилання все одно, але важливо підкреслити це ...
Лев,

@Leo Це хороший момент. ArrayList - це Collection, але він підтримується масивом, тому нормальне значення для нього краще.
aliteralmind

Я думаю, що for(int value : int_array) {/* loop content */}тест є найповільнішим у вашому тесті, оскільки він синтаксично еквівалентний for(int i = 0; i < int_array.length; i++) {int value = int_array[i]; /* loop content */}, що не з чим тест порівнює.
дайског

(до речі, я не кажу, що ваш тест недійсний, але, можливо, варто відзначити причини, що стоять за різницею, щоб люди могли вибрати те, що підходить для їх конкретного сценарію. Якщо вони роблять int value = int_array[i];на початку свого цикл, тоді вони також можуть використовувати foreach. Якщо тільки їм не потрібен доступ до індексу, чомусь також. Коротше, все залежить від контексту.)
daiscog

129

Ось відповідь, яка не передбачає знання Java Ітераторів. Він менш точний, але корисний для освіти.

Під час програмування ми часто пишемо код, який виглядає наступним чином:

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.


40

Цикл для кожного циклу в Java використовує основний механізм ітератора. Тож він ідентичний наступному:

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

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

25

У функціях Java 8 ви можете використовувати це:

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

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

Вихідні дані

First
Second
Third

7
ця випадкова інформація навіть віддалено не відповідає на питання
Тім

25

Це має на увазі відповідь nsayer, але варто відзначити, що синтаксис ОП для (..) буде працювати, коли "someList" - це все, що реалізує java.lang.Iterable - це не повинно бути списком чи деякою колекцією з java.util. Тому навіть ваші власні типи можуть використовуватися з цим синтаксисом.


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

24

Як визначено в JLS, для кожного циклу може бути дві форми:

  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);

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

21

Конструкція циклу Java "для кожного" дозволить повторити два типи об'єктів:

  • T[] (масиви будь-якого типу)
  • java.lang.Iterable<T>

Iterable<T>Інтерфейс має тільки один метод: Iterator<T> iterator(). Це працює на об'єктах типу, Collection<T>оскільки Collection<T>інтерфейс розширюється Iterable<T>.


16

Поняття циклу передбачення, як згадується у Вікіпедії, висвітлено нижче:

Однак, на відміну від інших конструкцій циклу, петлі 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.


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);
});


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-циклу легше читати і знімає потребу в окремому ітераторі, але він справді корисний лише в ітераційних пропусках лише для читання.


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-every - це конструкція над колекцією, яка реалізує Iterator . Пам'ятайте, що у вашій колекції повинен бути реалізований Iterator ; інакше ви не можете використовувати його для кожного.

Наступний рядок читається як " для кожного TimerTask t у списку. "

for (TimerTask t : list)

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


8

Перед Java 8 вам потрібно використовувати наступне:

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

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

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

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

Більше про потоки ви можете знайти тут .


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цикл.


6

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

Їх найкраще використовувати, коли значення кроку є простим збільшенням 1 і коли вам потрібен лише доступ до поточного елемента циклу. Наприклад, якщо вам потрібно перетворити цикл на кожен елемент масиву або колекції, не зазирючи вперед або позаду поточного елемента.

Немає ініціалізації циклу, не булева умова, а значення кроку неявне і є простим збільшенням. Ось чому вони вважаються набагато простішими, ніж звичайні для петель.

Покращені петлі дотримуйтесь цього порядку виконання:

1) петлеве тіло

2) повторюватись з кроку 1 до тих пір, поки весь масив чи колекція не пройде

Приклад - Integer масив

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

Ми можемо використовувати цикл для кожного циклу для повторення масиву рядків. У декларації циклу зазначено: цикл на масив myStrings String та збереження поточного значення String у змінній currentString.

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

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

Вихід:

alpha
beta
gamma
delta

Приклад - Список

Покращений цикл можна також використовувати для ітерації через 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 і збережіть поточне значення List у змінній currentItem.

Вихід:

alpha
beta
gamma
delta

Приклад - Встановити

Покращений цикл може також використовуватися для повторення через 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. Зауважте, що оскільки це набір, дублюючі значення String не зберігаються.

Вихід:

alpha
delta
beta
gamma

Джерело: Петлі в Java - Ultimate Guide



3

Java для кожної ідіоми може бути застосована лише до масивів або об'єктів типу * Iterable . Ця ідіома неявна, оскільки вона справді підтримується ітератором. Ітератор програмується програмістом і часто використовує цілий індекс або вузол (залежно від структури даних) для відстеження своєї позиції. На папері це повільніше, ніж у звичайного циклу for, щонайменше для "лінійних" структур, таких як масиви та списки, але це забезпечує більшу абстракцію.


-1: це спосіб менш читабельний (як правило): навіть ваш власний приклад (перший) невірний, оскільки він залишає перший елемент у масиві.
Ондрей Скопек

2

Це виглядає божевільно, але ей це працює

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

Це працює. Магія


1
Для цього потрібна Java 1.8 +
BARNI

2
навіть не віддалено відповідає на питання
Тім

2

Як і багато інших відповідей правильно, for each loopце просто синтаксичний цукор над тим же самим старим, for loopі компілятор переводить його на те саме старе для циклу.

javac (відкритий 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);
            }
        }
    }
}

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


-2
List<Item> Items = obj.getItems();
for(Item item:Items)
             {
                System.out.println(item); 
             }

Ітераціює над усіма об'єктами в таблиці елементів.


1
Користувач не запитував синтаксис
pradipgarala
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.