Pertanyaan Bagaimana cara kerja Java 'for each' loop?


Mempertimbangkan:

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

Apa yang akan setara for loop terlihat seperti tanpa menggunakan untuk setiap sintaksis?


1200
2017-09-17 16:44


asal


Jawaban:


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

Perhatikan bahwa jika Anda perlu menggunakannya i.remove(); dalam loop Anda, atau mengakses iterator yang sebenarnya dalam beberapa cara, Anda tidak dapat menggunakan for ( : ) idiom, karena iterator yang sebenarnya hanya disimpulkan.

Seperti dicatat oleh Denis Bueno, kode ini berfungsi untuk setiap objek yang mengimplementasikan Iterable antarmuka.

Juga, jika sisi kanan for (:) idiom adalah sebuah array bukan sebuah Iterable objek, kode internal menggunakan penghitung indeks int dan memeriksa array.length sebagai gantinya. Lihat Spesifikasi Bahasa Jawa.


967
2017-09-17 16:46



Konstruk untuk setiap juga berlaku untuk array. misalnya

String[] fruits = new String[] { "Orange", "Apple", "Pear", "Strawberry" };

for (String fruit : fruits) {
    // fruit is an element of the `fruits` array.
}

yang pada dasarnya setara dengan

for (int i = 0; i < fruits.length; i++) {
    String fruit = fruits[i];
    // fruit is an element of the `fruits` array.
}

Jadi, ringkasan keseluruhan:
[nsayer] Berikut ini adalah bentuk yang lebih panjang dari apa yang terjadi:

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

Perhatikan bahwa jika Anda perlu menggunakannya   i.remove (); dalam lingkaran Anda, atau akses   iterator yang sebenarnya dalam beberapa cara, Anda   tidak bisa menggunakan untuk (:) idiom, sejak   Iterator yang sebenarnya hanyalah   disimpulkan.

[Denis Bueno]

Itu tersirat oleh jawaban nsayer, tapi   perlu dicatat bahwa OP untuk (..)   sintaks akan bekerja ketika "someList" adalah   apa pun yang diimplementasikan   java.lang.Iterable - tidak ada   menjadi daftar, atau beberapa koleksi dari   java.util. Bahkan tipemu sendiri,   oleh karena itu, dapat digunakan dengan ini   sintaksis.


423
2017-09-17 17:06



Berikut ini adalah jawaban yang tidak menganggap pengetahuan Iterators Java. Ini kurang tepat, tetapi berguna untuk pendidikan.

Saat memprogram kami sering menulis kode yang terlihat seperti berikut:

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

Sintaksis foreach memungkinkan pola umum ini ditulis dengan cara yang lebih alami dan kurang sintaksis.

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

Selain itu sintaks ini berlaku untuk objek seperti Daftar atau Set yang tidak mendukung pengindeksan array, tetapi yang mengimplementasikan antarmuka Java Iterable.


119
2017-10-31 16:35



Itu foreach lingkaran, ditambahkan Java 5 (Juga disebut "enhanced for loop"), setara dengan menggunakan a java.util.Iterator- itu gula sintaksis untuk hal yang sama. Oleh karena itu, ketika membaca setiap elemen, satu per satu dan berurutan, a foreach harus selalu dipilih melalui iterator, karena lebih mudah dan ringkas.

untuk setiap

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

Iterator

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

Ada situasi di mana Anda harus menggunakan Iterator langsung. Misalnya, mencoba menghapus elemen saat menggunakan foreach dapat (akan?) menghasilkan a ConcurrentModificationException.

foreach vs. for: Perbedaan dasar

Satu-satunya perbedaan praktis antara for dan foreach adalah bahwa, dalam kasus objek yang dapat diindeks, Anda tidak memiliki akses ke indeks. Contoh saat dasar for lingkaran diperlukan:

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

Meskipun Anda dapat secara manual membuat indeks int-variabel terpisah dengan foreach,

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

itu tidak dianjurkan, karena ruang lingkup variabel tidak ideal, dan dasar for loop hanyalah format standar dan yang diharapkan untuk kasus penggunaan ini.

foreach vs. for: Kinerja

Saat mengakses koleksi, a foreach aku s jauh lebih cepat dari dasar for akses array loop. Ketika mengakses array, bagaimanapun - setidaknya dengan primitif dan wrapper-array - akses melalui indeks secara dramatis lebih cepat.

Mengatur waktu perbedaan antara iterator dan akses indeks untuk int-array primitif

Indeks adalah 23-40 persen lebih cepat daripada iterator saat mengakses int atau Integer array. Berikut adalah output dari kelas pengujian di bagian bawah posting ini, yang menjumlahkan angka-angka dalam array primitif-int 100-elemen (A adalah iterator, B adalah indeks):

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

Saya juga menjalankan ini untuk sebuah Integer larik, dan indeks masih merupakan pemenang yang jelas, tetapi hanya antara 18 dan 25 persen lebih cepat.

Untuk koleksi, iterator lebih cepat daripada indeks

Untuk sebuah List dari IntegersNamun, iterator adalah pemenang yang jelas. Ubah saja int-array di kelas tes untuk:

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

Dan buat perubahan yang diperlukan pada fungsi-test (int[] untuk List<Integer>, length untuk size(), dll.):

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

Dalam satu tes mereka hampir setara, tetapi dengan koleksi, iterator menang.

* Posting ini didasarkan pada dua jawaban yang saya tulis di Stack Overflow:

Beberapa informasi lebih lanjut: Mana yang lebih efisien, untuk setiap loop, atau iterator?

Kelas pengujian penuh

Saya membuat kelas ini dengan membandingkan waktu yang dibutuhkan untuk melakukan apa saja setelah membaca pertanyaan ini di Stack Overflow:

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;https://stackoverflow.com/questions/180158/how-do-i-time-a-methods-execution-in-java&quot;&gt;https://stackoverflow.com/questions/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

}

114
2018-03-01 12:47



The for-each loop di Java menggunakan mekanisme iterator yang mendasarinya. Jadi ini identik dengan yang berikut:

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

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

34
2017-09-17 16:46



Di fitur Java 8 Anda dapat menggunakan ini:

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

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

Keluaran

First
Second
Third

21
2018-04-19 15:22



Ini tersirat oleh jawaban nsayer, tapi perlu dicatat bahwa OP untuk (..) sintaks akan bekerja ketika "someList" adalah apa pun yang mengimplementasikan java.lang.Iterable - itu tidak harus daftar, atau beberapa koleksi dari java.util. Bahkan tipe Anda sendiri, oleh karena itu, dapat digunakan dengan sintaks ini.


19
2017-09-17 16:50