Làm thế nào để vòng lặp Java 'cho mỗi' hoạt động?


1498

Xem xét:

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

forVòng lặp tương đương sẽ trông như thế nào nếu không sử dụng cho mỗi cú pháp?


Theo JLS, nó có hai dạng: stackoverflow.com/a/33232565/1216775
akhil_mittal

Câu trả lời:


1175
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 mình hoặc truy cập vào 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ữ này, vì trình lặp thực tế chỉ được suy ra.

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 Iterablegiao diện .

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


14
Tôi đã tìm thấy chỉ gọi một vòng lặp while như while (someList.hasMoreElements ()) {// làm gì đó}} - giúp tôi gần với ân sủng mã hóa mà tôi hy vọng tìm thấy khi tôi tìm kiếm câu hỏi này.
James T Snell

6
Đồng thời xem docs.oracle.com/javase/1.5.0/docs/guide/lingu/foreach.html giải thích vòng lặp foreach (khi nó được giới thiệu)
PhoneixS

1
dành cho nhà phát triển studio android: import java.util.Iterator;import java.lang.Iterable;
dsdsdsdsd

Frustratingly, java.util.Iteratorkhông thực hiện Iterable, do đó bạn có thể không for(String s : (Iterator<String>)foo). Tôi hiểu tại sao điều này là, nhưng nó khó chịu.
Christopher Schultz

499

Cấu trúc cho mỗi cũng có giá trị 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 là 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à dạng 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 vào trình lặp thực tế theo một cách nào đó, bạn không thể sử dụng thành ngữ for (:) vì Iterator thực tế chỉ được suy ra.

[Denis Bueno]

Nó được ngụ ý bởi câu trả lời của người dùng, nhưng đáng chú ý là cú pháp của OP cho (..) sẽ hoạt động khi "someList" là bất cứ thứ gì thực hiện java.lang.Iterable - nó không phải là một danh sách hoặc một bộ sưu tập nào đó 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.


161

Các foreachvòng lặp , bổ sung trong Java 5 (hay còn gọi là "tăng cường cho vòng lặp"), tương đương với sử dụng một java.util.Iteratorđường cú pháp của --it cho điều tương tự. Do đó, khi đọc từng phần tử, từng phần một và theo thứ tự, foreachluôn luôn phải chọn một phần tử lặp, vì nó thuận tiện và ngắn gọn hơn.

cho mỗi

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

Lặp lại

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 Iteratortrực tiếp. Ví dụ: cố gắng xóa một phần tử trong khi sử dụng foreachkết quả có thể (sẽ?) Trong a ConcurrentModificationException.

foreachvs for.: Sự khác biệt cơ bản

Sự khác biệt thực tế duy nhất giữa forforeachlà, trong trường hợp các đố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 forvòng lặp cơ bản được yêu cầu:

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

Mặc dù bạn bằng tay có thể tạo ra một chỉ số riêng biệt int biến với foreach,

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

không nên, vì phạm vi biến không lý tưởng và forvòng lặp cơ bản chỉ đơn giản là định dạng chuẩn và dự kiến ​​cho trường hợp sử dụng này.

foreachvs for: Hiệu suất

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

Định thời gian cho sự khác biệt giữa truy cập iterator và chỉ mục cho các mảng int nguyên thủy

Các chỉ mục nhanh hơn 23- 40 phần trăm so với các trình vòng lặp khi truy cập inthoặc Integermảng. Đây là đầu ra từ lớp thử nghiệm ở dưới cùng của bài đăng này, tính tổng các số trong một mảng nguyên thủy 100 phần tử (A là iterator, 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 đã chạy nó cho một Integermảng và các 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%.

Đố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

Đối với một Listsố Integerstuy nhiên,, vòng lặp là người chiến thắng rõ ràng. Chỉ cần thay đổi mảng int trong lớp thử nghiệm 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 chức năng kiểm tra ( 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, iterator 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: Cái nào hiệu quả hơn, vòng lặp for-every hoặc iterator?

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

Tôi đã tạo ra lớp so sánh-thời gian-thời gian cần làm này 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;/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
Câu trả lời này hiện là một bài đăng trên blog và được tạo ra từ hai câu trả lời liên quan mà tôi đã viết: ở đâyở đây . Nó cũng bao gồm một lớp hữu ích chung để so sánh tốc độ của hai chức năng (ở phía dưới).
aliteralmind

1
Chỉ cần một nhận xét nhỏ ở đây, bạn không nên nói rõ rằng cú pháp for (:) luôn tốt hơn để truy cập các bộ sưu tập; nếu bạn đang sử dụng danh sách mảng, vòng lặp for (:) sẽ chậm hơn khoảng 2 lần so với sử dụng for (int i = 0, len = ArrayList.size (); i <len; i ++). Tôi nghĩ rằng bạn đã đề cập rằng trong liên kết [link] ( stackoverflow.com/questions/2113216/ triệt), nhưng điều quan trọng là làm nổi bật điều đó ...
Leo

@Leo Đó là một điểm tốt. Một 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 cho 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ề mặt 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.
daiscog

(nhân tiện, tôi không nói rằng bài kiểm tra của bạn không hợp lệ, nhưng có thể đáng chú ý những lý do đằng sau sự khác biệt để mọi người có thể chọn những gì phù hợp với kịch bản cụ thể của họ. Nếu họ đang thực hiện int value = int_array[i];khi bắt đầu vòng lặp, sau đó họ cũng có thể sử dụng foreach. Trừ khi họ cần truy cập vào chỉ mục, vì một số lý do. Tóm lại, tất cả phụ thuộc vào ngữ cảnh.)
daiscog

129

Đây là một câu trả lời không thừa nhận kiến ​​thức về các trình vòng lặp Java. Nó ít chính xác hơn, nhưng nó hữu ích cho giáo dục.

Trong khi lập trình, chúng ta thường viết mã trô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 chung này được viết theo cách tự nhiên hơn và ít ồn hơn về mặt cú pháp.

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

Ngoài ra, cú pháp này 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 Iterable Java.


40

Vòng lặp for-Each trong Java sử dụng cơ chế lặp lặp bên dưới. 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);
}

25

Trong các tính năng của 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

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

25

Nó được ngụ ý bởi câu trả lời của người dùng, nhưng đáng chú ý là cú pháp của OP cho (..) sẽ hoạt động khi "someList" là bất cứ thứ gì thực hiện java.lang.Iterable - nó không phải là một danh sách hoặc một bộ sưu tập nào đó 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.


1
fd là đúng - mã nội bộ khi phía bên phải của thành ngữ for (:) sử dụng int và Array.length thay vì tìm nạp Iterator. forum.sun.com/thread.jspa?messageID=2743233
nsayer

24

Như được định nghĩa trong JLS cho mỗi vòng lặp có thể có hai dạng:

  1. Nếu loại Biểu thức là một kiểu con Iterablethì dịch là:

    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. Nếu Biểu thức nhất thiết phải có kiểu mảng T[]thì:

    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 đã giới thiệu các luồng hoạt động thường tốt hơn. Chúng ta có thể sử dụng chúng như:

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

2
Câu trả lời phù hợp và chính xác nhất. Enchansed cho có hai bản dịch thực sự.
Zarial

23

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 bằng vòng lặp foreach, nhưng bạn KHÔNG thể khởi tạo chúng. Sử dụng forvòng lặp ban đầu cho điều đó.

CẢNH BÁO: Bạn phải khớp loại của 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 thành phần, hãy sử dụng forvòng lặp ban đầu 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 bàn điều khiển, chúng ta sẽ nhận được:

hello
2 is cool
hello
hello

21

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

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

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


16

Khái niệm về vòng lặp foreach như được đề cập trong Wikipedia được nêu bật bên dưới:

Tuy nhiên, không giống như các cấu trúc vòng lặp khác, các vòng lặp foreach thường không duy trì bộ đếm rõ ràng : về cơ bản chúng nói "làm điều này với mọi thứ trong tập hợp này", thay vì "làm điều này x lần". Điều này tránh tiềm năng off-by-one lỗi và làm cho mã đơn giản hơn để đọc.

Vì vậy, khái niệm về vòng lặp foreach mô tả rằng vòng lặp không sử dụng bất kỳ bộ đếm rõ ràng nào, điều đó có nghĩa là không cần sử dụng các chỉ mục để duyệt qua danh sách, do đó nó giúp người dùng không bị lỗi. Để mô tả khái niệm chung về lỗi này, chúng ta hãy lấy một ví dụ về vòng lặp để duyệt qua danh sách bằng các chỉ mục.

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

}

Nhưng giả sử nếu danh sách bắt đầu với chỉ số 1 thì vòng lặp này sẽ đưa ra một ngoại lệ vì nó sẽ không tìm thấy phần tử nào ở chỉ số 0 và lỗi này được gọi là lỗi do lỗi. Vì vậy, để tránh lỗi này, một khái niệm về vòng lặp foreach được sử dụng. Có thể có những lợi thế khác nữa, nhưng đây là những gì tôi nghĩ là khái niệm chính và lợi thế của việc sử dụng vòng lặp foreach.


13

Trong Java 8, họ đã giới thiệu forEach. Sử dụng nó Danh sách, Bản đồ có thể được lặp.

Lặp lại một danh sách bằng cách sử dụng cho mỗi

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

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

hoặc là

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

Lặp lại Bản đồ bằng cách sử dụng cho mỗi

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

hoặc là

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

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

11

Sử dụng các phiên bản Java cũ hơn bao gồm cả Java 7bạn có thể sử dụng foreachvòng lặp như sau.

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

Sau đây là cách sử dụng foreachvòng lặp mới nhất trongJava 8

(lặp một Danh sách với forEachbiểu thức + lambda hoặc tham chiếu phương thức)

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

Để biết thêm thông tin tham khảo liên kết này.

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


10

Đây là một biểu thức tương đương.

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

10

Cũng lưu ý rằng việc sử dụng phương pháp "foreach" trong câu hỏi ban đầu có một số hạn chế, chẳng hạn như không thể xóa các mục khỏi danh sách trong quá trình lặp.

Vòng lặp for mới dễ đọc hơn và loại bỏ sự cần thiết của một trình vòng lặp riêng biệt, nhưng chỉ thực sự có thể sử dụng được trong các lần lặp chỉ đọc.


1
Trong những trường hợp đó, việc sử dụng removeIfcó thể là công cụ phù hợp
ncmathsadist

9

Một thay thế cho forEach để tránh "cho mỗi" của bạn:

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

Biến thể 1 (đồng bằng):

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

Biến 2 (thực thi song song (nhanh hơn)):

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

2
Đáng

Chúng tôi không thể chắc chắn 100% rằng cùng một chủ đề được sử dụng. Tôi thích sử dụng for(biểu mẫu nếu tôi muốn đảm bảo cùng một chủ đề được sử dụng. Tôi thích sử dụng dạng luồng nếu tôi muốn cho phép thực thi đa luồng.
Grim

8

Nó thêm vẻ đẹp cho mã của bạn bằng cách loại bỏ tất cả các lộn xộn vòng lặp cơ bản. Nó cung cấp một cái nhìn rõ ràng cho mã của bạn, được chứng minh dưới đây.

forVòng lặp thông thường :

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

Sử dụng cho mỗi:

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

cho mỗi cái là một cấu trúc trên một bộ sưu tập thực hiện Iterator . Hãy nhớ rằng, bộ sưu tập của bạn nên thực hiện Iterator ; nếu không, bạn không thể sử dụng nó cho mỗi.

Dòng sau được đọc là " cho mỗi t TimerTask trong danh sách. "

for (TimerTask t : list)

Có ít cơ hội hơn cho các lỗi trong trường hợp cho mỗi. Bạn không phải lo lắng về việc khởi tạo iterator hoặc khởi tạo bộ đếm vòng lặp và chấm dứt nó (nơi có phạm vi cho các lỗi).


8

Trước Java 8, bạn cần sử dụng như sau:

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

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

Tuy nhiên, với việc giới thiệu Luồng trong Java 8, bạn có thể thực hiện điều tương tự với cú pháp ít hơn nhiều. Ví dụ, đối với bạn, someListbạn có thể làm:

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

Bạn có thể tìm thêm về các luồng ở đây .


The foreach loop, added in Java 5 (also called the "enhanced for loop"), is equivalent to using a java.util.Iterator
Alex78191

7

Nó sẽ trông giống như thế này. Rất giòn.

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

Có một bài viết tốt cho mỗi tài liệu trong Mặt trời .


6

Như rất nhiều câu trả lời hay đã nói, một đối tượng phải thực hiện Iterable interfacenếu nó muốn sử dụng một for-eachvòng lặp.

Tôi sẽ đăng một ví dụ đơn giản và cố gắng giải thích theo cách khác cách for-eachvòng lặp hoạt động.

Các for-eachví dụ vòng lặp:

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

Sau đó, nếu chúng ta sử dụng javapđể dịch ngược lớp này, chúng ta sẽ lấy mẫu mã byte này:

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;

Như chúng ta có thể thấy từ dòng cuối cùng của mẫu, trình biên dịch sẽ tự động chuyển đổi việc sử dụng for-eachtừ khóa sang sử dụng từ Iteratorlúc biên dịch. Điều đó có thể giải thích tại sao đối tượng, không thực hiện Iterable interface, sẽ ném Exceptionkhi nó cố gắng sử dụng for-eachvòng lặp.


6

Các Java cho mỗi vòng lặp (aka tăng cường cho vòng lặp) là một phiên bản đơn giản của một vòng lặp for. Ưu điểm là có ít mã để viết và ít biến hơn để quản lý. Nhược điểm là bạn không có quyền kiểm soát giá trị bước và không có quyền truy cập vào chỉ mục vòng lặp bên trong thân vòng lặp.

Chúng được sử dụng tốt nhất khi giá trị bước là gia số đơn giản là 1 và khi bạn chỉ cần truy cập vào phần tử vòng lặp hiện tại. Ví dụ: nếu bạn cần lặp qua mọi phần tử trong một mảng hoặc Bộ sưu tập mà không nhìn trộm phía trước hoặc phía sau phần tử hiện tại.

Không có khởi tạo vòng lặp, không có điều kiện boolean và giá trị bước là ẩn và là một bước tăng đơn giản. Đây là lý do tại sao chúng được coi là đơn giản hơn nhiều so với thông thường cho các vòng lặp.

Tăng cường cho các vòng lặp theo thứ tự thực hiện này:

1) thân vòng

2) lặp lại từ bước 1 cho đến khi toàn bộ mảng hoặc bộ sưu tập đã được duyệt qua

Ví dụ - Mảng số nguyên

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

Biến currentValue giữ giá trị hiện tại được lặp trong mảng intArray. Lưu ý rằng không có giá trị bước rõ ràng - nó luôn luôn tăng 1.

Các dấu hai chấm có thể được nghĩ đến có nghĩa là trong tiếng Anh. Vì vậy, trạng thái khai báo vòng lặp nâng cao: lặp qua intArray và lưu trữ giá trị int mảng hiện tại trong biến currentValue.

Đầu ra:

1
3
5
7
9

Ví dụ - Mảng chuỗi

Chúng ta có thể sử dụng vòng lặp for-Each để lặp qua một chuỗi các chuỗi. Khai báo vòng lặp trạng thái: lặp qua mảng Chuỗi myStrings và lưu trữ giá trị Chuỗi hiện tại trong biến currentString.

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

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

Đầu ra:

alpha
beta
gamma
delta

Ví dụ - Danh sách

Vòng lặp for được tăng cường cũng có thể được sử dụng để lặp qua java.util.List như sau:

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

Khai báo vòng lặp trạng thái: loop over myList List of String và lưu giá trị List hiện tại trong biến currentItem.

Đầu ra:

alpha
beta
gamma
delta

Ví dụ - Đặt

Vòng lặp for được tăng cường cũng có thể được sử dụng để lặp qua java.util.Set như sau:

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

Khai báo vòng lặp trạng thái: loop over my Set Set of String và lưu giá trị Set hiện tại trong biến currentItem. Lưu ý rằng vì đây là Tập hợp, các giá trị Chuỗi trùng lặp không được lưu trữ.

Đầu ra:

alpha
delta
beta
gamma

Nguồn: Vòng lặp trong Java - Hướng dẫn cơ bản


4
public static Boolean Add_Tag(int totalsize)
{ List<String> fullst = new ArrayList<String>();
            for(int k=0;k<totalsize;k++)
            {
              fullst.addAll();
            }
}

3

Chỉ thành ngữ Java cho mỗi thành ngữ chỉ có thể được áp dụng cho các mảng hoặc đối tượng kiểu * Iterable . Thành ngữ này được ngầm định vì nó thực sự được hỗ trợ bởi một Iterator. Iterator được lập trình viên lập trình và thường sử dụng một chỉ số nguyên hoặc một nút (tùy thuộc vào cấu trúc dữ liệu) để theo dõi vị trí của nó. Trên giấy, nó chậm hơn một vòng lặp for thông thường, ít nhất là đối với các cấu trúc "tuyến tính" như mảng và Danh sách nhưng nó cung cấp sự trừu tượng hóa lớn hơn.


-1: đây là cách ít dễ đọc hơn (nói chung): ngay cả ví dụ của bạn (ví dụ đầu tiên) cũng sai, vì nó bỏ qua phần tử đầu tiên trong mảng.
Ondrej Skopek 18/03/2016

2

Điều này có vẻ điên rồ nhưng hey nó hoạt động

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

Những công việc này. ma thuật


1
Điều này đòi hỏi Java 1.8 +
BARNI

2
thậm chí không trả lời từ xa câu hỏi
Tim

2

Như nhiều câu trả lời khác nêu chính xác, đường for each loopchỉ là cú pháp so với cùng một kiểu cũ for loopvà trình biên dịch sẽ dịch nó thành cùng một vòng lặp cũ.

javac (open jdk) có một công tắc -XD-printflat, tạo ra một tệp java với tất cả các đường cú pháp được loại bỏ. lệnh hoàn chỉnh trông như thế này

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

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

Vì vậy, hãy loại bỏ đường cú pháp

Để trả lời câu hỏi này, tôi đã tạo một tệp và viết hai phiên bản for each, một với arrayvà một với list. javatập tin của tôi trông như thế này

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

Khi tôi compiledtập tin này với chuyển đổi ở trên, tôi đã nhận được đầu ra sau đây.

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

Bạn có thể thấy rằng cùng với đường cú pháp khác (Autoboxing) cho mỗi vòng lặp đã được thay đổi thành các vòng lặp đơn giản.


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

Lặp lại tất cả các đối tượng trong bảng Mục.


1
Người dùng chưa yêu cầu cú pháp
pradipgarala
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.