Java 5는 for-each 루프를 제공해주었습니다.이 루프는 가능할 때마다 사용해야합니다.배열을 반복하는 관용구가 가장 효율적입니까?
블록의 배열 색인을 사용해야하는 경우 가장 효율적인 관용구는 무엇입니까?
// Option (1)
for (int i = array.length - 1; i >= 0; i--) {
// Code.
}
// Option (2)
for (int i = 0; i < array.length; i++) {
// Code.
}
// Option (3)
for (int i = 0, n = array.length; i < n; i++) {
// Code.
}
는 (물론,이. 대부분의 프로그램하지만 유머 나에게 큰 성능 차이를하지 않습니다)
거꾸로 반복하고 끔찍한입니다 :-). 어쩌면 비우호적 인 캐시일까요? 또는 현대 가공업자가 메모리에서 뒤로 걷는 것을 감지 할 수 있습니까?
이 짧고 JIT 컴파일러가
array
이 변경되지 않으므로length
이 본질적으로 (3)으로 바뀔 수 있다는 것을 알 수 있습니다. 하지만 그렇게 할 수 있습니까? 그것은 상한의 일부Collection.size()
을인지이 가장 빠른 옵션으로 Effective Java에서 항목 45 여호수아 블로흐에 의해 제안 (JVM이 오라클의 핫스팟/자바 7이라고 가정). 그러나 배열에도 적용됩니까? 바이트 코드 (아래 참조)에서 사이클당 (사전 최적화 된)
arraylength
명령어를 저장한다는 것을 알 수 있습니다. 달빅 가상 머신에서 루프에 대한
This question, 목록 (1) - (3)과 같은 빠른 느린합니다. 그러나 2008 년 정보는 Dalvik이 훨씬 더 성숙한 것이므로 지금도 그렇게 생각하지 않습니다. 위의 예에서 생성 된 바이트 코드를 보면
, 분명한 차이점이 있습니다
가Compiled from "ForLoops.java"
public class ForLoops extends java.lang.Object{
static int[] array;
public ForLoops();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: return
public static void forLoop1();
Code:
0: getstatic #17; //Field array:[I
3: arraylength
4: iconst_1
5: isub
6: istore_0
7: goto 13
10: iinc 0, -1
13: iload_0
14: ifge 10
17: return
public static void forLoop2();
Code:
0: iconst_0
1: istore_0
2: goto 8
5: iinc 0, 1
8: iload_0
9: getstatic #17; //Field array:[I
12: arraylength
13: if_icmplt 5
16: return
public static void forLoop3();
Code:
0: iconst_0
1: istore_0
2: getstatic #17; //Field array:[I
5: arraylength
6: istore_1
7: goto 13
10: iinc 0, 1
13: iload_0
14: iload_1
15: if_icmplt 10
18: return
}
이론상 'array.length'는 한 번만 평가하면되기 때문에 일반적으로 1과 3이 2보다 효율적입니다. 그러나 Java에서'길이'를 평가하는 것은 매우 간단합니다. 특히 JITCed 인 경우 특히 그렇습니다. 따라서 이론적 인 차이점은 모두 실제로 사라지지만 말입니다. 대부분의 경우 루프 본문의 내용과 JITC 최적화 프로그램이 루프 본문과 루프 제어를 병합하는 방식에 따라 다릅니다. –
@Nicholas 좋은 일이 바이트 코드를 꺼내! 그러나 바이트 코드가 궁극적으로 JIT로 인해 실행되는 것이 아니라는 점을 명심해야합니다. 우리가 JITed 지침을 얻을 수 있다면, 그것은 최종 답이 될 것이지만 이것은 (a) 플랫폼에 따라 다르며 (b) JITing의 "수준"이 다르므로 비현실적입니다. 또한 런타임 중에 생성 된 코드에 투명성을 부여하는 JIT에 대해서는 알지 못합니다. 최소한 JVM 메모리 공간을 직접 살펴 봐야합니다. – sigpwned
"가장 효율적인"선택은 일반적으로 나머지 코드에 가장 적합한 선택이라는 점을 지적해야합니다. 예를 들어, 거꾸로 반복하는 것은 때로는 어색하고 때로는 매우 유용합니다. 마찬가지로 배열 객체가 루프 내부에서 대체되면 각 반복에서'array.length'를 확인하는 것이 실제로 필요할 수 있습니다. –