foreach
어쨌든 후드 아래에서 반복자를 사용합니다. 그것은 단지 구문 설탕입니다.
다음 프로그램을 고려하십시오.
import java.util.List;
import java.util.ArrayList;
public class Whatever {
private final List<Integer> list = new ArrayList<>();
public void main() {
for(Integer i : list) {
}
}
}
의와 함께 컴파일하자 javac Whatever.java
,
그리고의 분해 바이트 코드를 읽어 main()
사용 javap -c Whatever
:
public void main();
Code:
0: aload_0
1: getfield #4 // Field list:Ljava/util/List;
4: invokeinterface #5, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
9: astore_1
10: aload_1
11: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
16: ifeq 32
19: aload_1
20: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
25: checkcast #8 // class java/lang/Integer
28: astore_2
29: goto 10
32: return
우리는 foreach
다음과 같은 프로그램으로 컴파일 되는 것을 볼 수 있습니다 .
- 다음을 사용하여 반복자를 만듭니다.
List.iterator()
- If
Iterator.hasNext()
: Iterator.next()
루프를 호출 하고 계속합니다
에 관해서는? "이 쓸모없는 루프가 컴파일 된 코드의 밖으로 최적화되지 않는 이유를 우리는 목록 항목으로 아무것도하지 않는 것을 볼 수있다"음, 코드 당신의 반복 가능한 그런 당신을 위해 가능 .iterator()
부작용이있다 또는 .hasNext()
부작용 또는 의미있는 결과가있는 것입니다.
데이터베이스에서 스크롤 가능한 쿼리를 나타내는 iterable .hasNext()
이 데이터베이스에 접속하거나 결과 세트의 끝에 도달하여 커서를 닫는 것과 같이 극적인 일을 할 수 있다고 쉽게 상상할 수 있습니다 .
따라서 루프 본문에서 아무 일도 일어나지 않는다는 것을 증명할 수 있지만 반복 할 때 의미 있고 결과적인 일이 발생하지 않음을 증명하는 것이 더 비쌉니다. 컴파일러는이 빈 루프 본문을 프로그램에 그대로 두어야합니다.
우리가 기대할 수있는 최선은 컴파일러 경고 일 것 입니다. 이 빈 루프 바디에 대해 경고 javac -Xlint:all Whatever.java
하지 않는 것이 흥미 롭습니다 . 그러나 IntelliJ IDEA는 그렇게합니다. 필자는 Eclipse 컴파일러를 사용하도록 IntelliJ를 구성했지만 그 이유가 아닐 수도 있습니다.