Câu hỏi Java 'cho mỗi vòng lặp hoạt động như thế nào?


Xem xét:

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

Điều gì tương đương for vòng lặp trông giống như không sử dụng cho mỗi cú pháp?


1203
2017-09-17 16:44


gốc




Các câu trả lời:


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

Lưu ý rằng nếu bạn cần sử dụng i.remove(); trong vòng lặp của bạn hoặc truy cập trình lặp thực tế theo một cách nào đó, bạn không thể sử dụng for ( : ) thành ngữ, vì trình lặp thực tế chỉ là suy luận.

Như đã được ghi nhận bởi Denis Bueno, mã này hoạt động cho bất kỳ đối tượng nào thực hiện Iterable giao diện.

Ngoài ra, nếu phía bên tay phải của for (:) thành ngữ là một array chứ không phải là Iterable đối tượng, mã nội bộ sử dụng bộ đếm chỉ mục int và kiểm tra array.length thay thế. Xem Đặc tả ngôn ngữ Java.


970
2017-09-17 16:46



Tôi đã tìm thấy chỉ cần gọi một vòng lặp trong khi while (someList.hasMoreElements ()) {// làm điều gì đó}} - đưa tôi đến gần ân điển mã hóa tôi hy vọng sẽ tìm thấy khi tôi tìm kiếm câu hỏi này. - James T Snell
Cũng thấy docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.htmlgiải thích vòng lặp foreach (khi nó được giới thiệu) - PhoneixS
dành cho nhà phát triển studio android: import java.util.Iterator; và import java.lang.Iterable; - dsdsdsdsd


Xay dung cho mỗi cũng hợp lệ cho mảng. ví dụ.

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

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

về cơ bản tương đương với

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

Vì vậy, tóm tắt tổng thể:
[nsayer] Sau đây là hình thức dài hơn của những gì đang xảy ra:

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

Lưu ý rằng nếu bạn cần sử dụng   i.remove (); trong vòng lặp của bạn, hoặc truy cập   trình lặp thực tế theo cách nào đó, bạn   không thể sử dụng thành ngữ for (:), vì   Iterator thực sự chỉ đơn thuần là   suy ra.

[Denis Bueno]

Nó được ngụ ý bởi câu trả lời của nsayer, nhưng   nó đáng chú ý là OP cho (..)   cú pháp sẽ hoạt động khi "someList" là   bất cứ thứ gì thực hiện   java.lang.Iterable - nó không có   là danh sách hoặc một số bộ sưu tập từ   java.util. Ngay cả các loại của riêng bạn,   do đó, có thể được sử dụng với điều này   cú pháp.


424
2017-09-17 17:06





Đây là một câu trả lời mà không giả định kiến ​​thức của các Iterator Java. Nó ít chính xác hơn, nhưng nó rất hữu ích cho giáo dục.

Trong khi lập trình, chúng ta thường viết mã trông giống như sau:

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

Cú pháp foreach cho phép mô hình phổ biến này được viết theo cách tự nhiên và ít cú pháp hơn.

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

Ngoài ra cú pháp này là hợp lệ cho các đối tượng như Danh sách hoặc Bộ không hỗ trợ lập chỉ mục mảng, nhưng thực hiện giao diện Java Iterable.


119
2017-10-31 16:35





Các foreach vòng lặp, được thêm vào Java 5 (còn được gọi là "tăng cường cho vòng lặp"), tương đương với việc sử dụng java.util.Iterator- Đường cú pháp của nó cho cùng một thứ. Do đó, khi đọc từng phần tử, từng cái một và theo thứ tự, foreach nên luôn được chọn trên một trình lặp, vì nó thuận tiện và súc tích hơn.

cho mỗi

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

Có những tình huống mà bạn phải sử dụng Iterator trực tiếp. Ví dụ: cố xóa một phần tử trong khi sử dụng foreach có thể (sẽ?) dẫn đến ConcurrentModificationException.

foreach so với for: Sự khác biệt cơ bản

Sự khác biệt thực tế duy nhất giữa for và foreach là, trong trường hợp đối tượng có thể lập chỉ mục, bạn không có quyền truy cập vào chỉ mục. Một ví dụ khi cơ bản for vòng lặp là bắt buộc:

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

Mặc dù bạn có thể tự tạo một biến chỉ mục riêng biệt với foreach,

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

nó không được khuyến khích, vì phạm vi biến đổi không phải là lý tưởng và cơ bản for vòng lặp đơn giản là định dạng chuẩn và được mong đợi cho trường hợp sử dụng này.

foreach so với for: Hiệu suất

Khi truy cập bộ sưu tập, một foreach Là nhanh hơn đáng kể hơn cơ bản for truy cập mảng của vòng lặp. Tuy nhiên, khi truy cập các mảng - ít nhất với các mảng nguyên thủy và bao bọc - truy cập thông qua các chỉ mục nhanh hơn đáng kể.

Định thời gian khác nhau giữa phép lặp và truy cập chỉ mục cho các mảng int nguyên thủy

Chỉ số là 23-40 phần trăm nhanh hơn các trình lặp khi truy cập int hoặc là Integer mảng. Đây là đầu ra từ lớp thử nghiệm ở cuối bài đăng này, tổng hợp các số trong một mảng nguyên tố-int 100 phần tử (A là trình lặp, B là chỉ mục):

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

Tôi cũng điều này cho một Integer mảng và chỉ mục vẫn là người chiến thắng rõ ràng, nhưng chỉ nhanh hơn từ 18 đến 25 phần trăm.

Đối với các bộ sưu tập, các trình vòng lặp nhanh hơn các chỉ mục

Cho một List của Integerstuy nhiên, vòng lặp là người chiến thắng rõ ràng. Chỉ cần thay đổi int-array trong lớp test thành:

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

Và thực hiện các thay đổi cần thiết cho hàm thử nghiệm (int[] đến List<Integer>, length đến size(), v.v.):

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

Trong một thử nghiệm, chúng gần như tương đương, nhưng với các bộ sưu tập, trình vòng lặp sẽ thắng.

* Bài đăng này dựa trên hai câu trả lời tôi đã viết trên Stack Overflow:

Một số thông tin khác: Đó là hiệu quả hơn, một vòng lặp cho mỗi, hoặc một iterator?

Lớp kiểm tra đầy đủ

Tôi đã tạo lớp học so sánh thời gian-nó-cần-to-do-bất-hai-thứ sau khi đọc câu hỏi này trên 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



Câu trả lời này bây giờ là bài viết trên blog và được tạo từ hai câu trả lời có liên quan mà tôi đã viết: đây và đây. Nó cũng bao gồm một lớp hữu ích chung để so sánh tốc độ của hai hàm (ở phía dưới). - aliteralmind
Chỉ cần một bình luận nhỏ ở đây, bạn không nên phân loại trạng thái cho cú pháp (:) luôn tốt hơn cho việc truy cập các bộ sưu tập; nếu bạn đang sử dụng một danh sách mảng, vòng lặp for (:) sẽ chậm hơn khoảng 2 x so với việc sử dụng (int i = 0, len = arrayList.size (); i <len; i ++). Tôi nghĩ bạn đã đề cập rằng trong [link] ( stackoverflow.com/questions/2113216/…) liên kết, nhưng điều quan trọng là làm nổi bật rằng ... - Leo
@Leo Đó là một điểm tốt. An ArrayList là Collection, nhưng nó được hỗ trợ bởi một mảng, đó là lý do tại sao bình thường là tốt hơn cho nó. - aliteralmind
Tôi tưởng tượng for(int value : int_array) {/* loop content */} là chậm nhất trong thử nghiệm của bạn bởi vì nó tương đương với cú pháp for(int i = 0; i < int_array.length; i++) {int value = int_array[i]; /* loop content */}, đó không phải là những gì thử nghiệm của bạn so sánh. - megaflop
lời giải thích hay!! - Yohan Malshika


Vòng lặp for-each trong Java sử dụng cơ chế lặp cơ bản. Vì vậy, nó giống hệt như sau:

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

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

34
2017-09-17 16:46





Trong các tính năng Java 8, bạn có thể sử dụng tính năng này:

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

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

Đầu ra

First
Second
Third

21
2018-04-19 15:22



thông tin ngẫu nhiên này thậm chí không trả lời câu hỏi từ xa - Tim Castelijns


Nó được ngụ ý bởi câu trả lời của nsayer, nhưng đáng chú ý là cú pháp OP (()) của OP sẽ hoạt động khi "someList" là bất cứ điều gì thực hiện java.lang.Iterable - nó không phải là một danh sách, hoặc một số bộ sưu tập từ java.util. Ngay cả các loại của riêng bạn, do đó, có thể được sử dụng với cú pháp này.


19
2017-09-17 16:50



Ngoài ra, bởi một số mảng đối tượng ma thuật xảo quyệt cũng hoạt động. - Mike Tunnicliffe
fd là đúng - mã bên trong khi phía bên tay phải của (:) thành ngữ sử dụng một int và array.length thay vì tìm nạp một Iterator. forums.sun.com/thread.jspa?messageID=2743233 - nsayer


Cú pháp vòng lặp foreach là:

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

Thí dụ:

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

Đầu ra:

Java
Coffe
Is
Cool

CẢNH BÁO: Bạn có thể truy cập các phần tử mảng với vòng lặp foreach, nhưng bạn KHÔNG thể khởi tạo chúng. Sử dụng bản gốc for vòng lặp cho điều đó.

CẢNH BÁO: Bạn phải phù hợp với loại mảng với đối tượng khác.

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

Nếu bạn muốn chỉnh sửa các phần tử, hãy sử dụng phần tử gốc for vòng lặp như thế này:

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

Bây giờ nếu chúng ta đổ s vào giao diện điều khiển, chúng ta sẽ nhận được:

hello
2 is cool
hello
hello

18
2017-11-07 05:35





Cấu trúc vòng lặp Java "cho mỗi" sẽ cho phép lặp qua hai loại đối tượng:

  • T[]  (mảng bất kỳ loại nào)
  • java.lang.Iterable<T>

Các Iterable<T> giao diện chỉ có một phương thức: Iterator<T> iterator(). Điều này hoạt động trên các đối tượng thuộc loại Collection<T> bởi vì Collection<T> giao diện mở rộng Iterable<T>.


17
2017-09-17 18:04