[java] Java ‘for each’루프는 어떻게 작동합니까?

치다:

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

구문 에 대해for 를 사용하지 않고 동등한 루프는 어떻게 생겼 습니까?



답변

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

i.remove();루프에서 사용하거나 실제 반복자에 어떤 방식으로 액세스 해야하는 경우 for ( : )실제 반복자가 유추되기 때문에 관용구를 사용할 수 없습니다 .

Denis Bueno가 언급했듯이이 코드는 Iterable인터페이스 를 구현하는 모든 객체에서 작동합니다 .

또한 for (:)관용구 의 오른쪽 arrayIterable객체 가 아닌 경우 내부 코드는 int 인덱스 카운터를 사용하고 array.length대신 검사 합니다. Java 언어 사양을 참조하십시오 .


답변

각각 의 구문 배열에도 유효합니다. 예 :

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을 구현하는 것이면 OP의 for (..) 구문이 작동한다는 점은 주목할 가치가 있습니다. java.util. 따라서 자신의 유형조차도이 구문과 함께 사용할 수 있습니다.


답변

foreach루프 추가, 자바 (5) , (또한 “향상된 루프”라고 함)을 사용하는 것과 같습니다 java.util.Iterator같은 일에 대한 –it의 문법 설탕을. 따라서 각 요소를 하나씩 순서대로 읽을 때 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.

foreachvs. for: 기본 차이점

의 유일한 실제적인 차이 forforeach색인 오브젝트의 경우, 인덱스에 액세스 할 수없는 그이다. 기본 for루프가 필요한 예 :

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

를 사용하여 별도의 색인 int-variable을 수동으로 만들 수 있지만 foreach,

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

variable-scope 가 이상적이지 않으므로 기본 for루프는이 유스 케이스에 대한 표준적이고 예상되는 형식 일 뿐이 므로 권장 되지 않습니다 .

foreachvs. for: 성능

컬렉션에 액세스 할 때 a foreach는 기본 루프의 어레이 액세스 보다 훨씬 빠릅니다for . 그러나 적어도 기본 및 랩퍼 배열을 사용하여 배열에 액세스하면 인덱스를 통한 액세스가 훨씬 빠릅니다.

기본 int- 배열에 대한 반복자와 인덱스 액세스의 차이 타이밍

인덱스는 23-이다 (40) 에 액세스 할 때 반복자 % 이상 빠르게 int또는 Integer배열. 이 게시물의 맨 아래에있는 테스트 클래스의 출력은 100 요소 primitive-int 배열의 숫자를 합칩니다 (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 % 더 빠릅니다.

컬렉션의 경우 반복자는 인덱스보다 빠릅니다.

A의 ListIntegers, 그러나, 반복자는 확실한 승자입니다. 테스트 클래스에서 int-array를 다음과 같이 변경하십시오.

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>, lengthsize(), 등)

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

한 번의 테스트에서는 거의 동일하지만 컬렉션을 사용하면 반복자가 승리합니다.

*이 게시물은 내가 스택 오버플로에 쓴 두 가지 답변을 기반으로합니다.

더 많은 정보 : 어느 것이 더 효율적인지, for-each 루프 또는 반복자입니까?

전체 테스트 클래스

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

}


답변

다음은 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 인터페이스를 구현하는 목록 또는 세트와 같은 오브젝트에 유효합니다.


답변

Java의 for-each 루프는 기본 반복자 메커니즘을 사용합니다. 따라서 다음과 동일합니다.

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

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


답변

Java 8 기능에서는 다음을 사용할 수 있습니다.

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

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

산출

First
Second
Third


답변

그것은 nsayer의 대답에 의해 암시,하지만 “someList”이 때 OP가 있다고 지적 그것의 가치는 (..) 구문 작동합니다 아무것도 구현 java.lang.Iterable가 -가 목록 또는 일부 컬렉션에서 일 필요는 없습니다가 java.util. 따라서 자신의 유형조차도이 구문과 함께 사용할 수 있습니다.