Todays lesson is: What javac does with following methods, when compiled.

Assumptions:

  • Iterating over ArrayList vs. List generates optimized code, not creating Iterator (i.e. would optimize memory usage using RandomAccessList API), but using int index
  • Itearating over Object[] is faster than List/ArrayList
  • foreach loop for Object[] is as tight code as manual iteration

[code lang=”java”]
class OptimizedLoop {

void doLoop1_1(List pList) {
for (Object value : pList) {
System.out.println(value.toString());
}
}

void doLoop1_2(ArrayList pList) {
for (Object value : pList) {
System.out.println(value.toString());
}
}

void doLoop1_3(List pList) {
for (int i = 0; i < pList.size(); i++) { System.out.println(pList.get(i).toString()); } } void doLoop1_4(List pList) { for (int i = pList.size() - 1; i >= 0; i–) {
System.out.println(pList.get(i).toString());
}
}

void doLoop2_1(Object[] pList) {
for (Object value : pList) {
System.out.println(value.toString());
}
}

void doLoop2_2(Object[] pList) {
for (int i = 0; i < pList.length; i++) { System.out.println(pList[i].toString()); } } void doLoop2_3(Object[] pList) { for (int i = pList.length- 1; i >= 0; i–) {
System.out.println(pList[i].toString());
}
}
}
[/code]

And here are the results,

[code lang=”java”]
class OptimizedLoop {
OptimizedLoop();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object.””:()V
4: return

void doLoop1_1(java.util.List);
Code:
0: aload_1
1: invokeinterface #2, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
6: astore_2
7: aload_2
8: invokeinterface #3, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
13: ifeq 36
16: aload_2
17: invokeinterface #4, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
22: astore_3
23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_3
27: invokevirtual #6 // Method java/lang/Object.toString:()Ljava/lang/String;
30: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
33: goto 7
36: return

void doLoop1_2(java.util.ArrayList);
Code:
0: aload_1
1: invokevirtual #8 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
4: astore_2
5: aload_2
6: invokeinterface #3, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
11: ifeq 34
14: aload_2
15: invokeinterface #4, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
20: astore_3
21: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
24: aload_3
25: invokevirtual #6 // Method java/lang/Object.toString:()Ljava/lang/String;
28: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
31: goto 5
34: return

void doLoop1_3(java.util.List);
Code:
0: iconst_0
1: istore_2
2: iload_2
3: aload_1
4: invokeinterface #9, 1 // InterfaceMethod java/util/List.size:()I
9: if_icmpge 34
12: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
15: aload_1
16: iload_2
17: invokeinterface #10, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
22: invokevirtual #6 // Method java/lang/Object.toString:()Ljava/lang/String;
25: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: iinc 2, 1
31: goto 2
34: return

void doLoop1_4(java.util.List);
Code:
0: aload_1
1: invokeinterface #9, 1 // InterfaceMethod java/util/List.size:()I
6: iconst_1
7: isub
8: istore_2
9: iload_2
10: iflt 35
13: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
16: aload_1
17: iload_2
18: invokeinterface #10, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
23: invokevirtual #6 // Method java/lang/Object.toString:()Ljava/lang/String;
26: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: iinc 2, -1
32: goto 9
35: return

void doLoop2_1(java.lang.Object[]);
Code:
0: aload_1
1: astore_2
2: aload_2
3: arraylength
4: istore_3
5: iconst_0
6: istore 4
8: iload 4
10: iload_3
11: if_icmpge 37
14: aload_2
15: iload 4
17: aaload
18: astore 5
20: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
23: aload 5
25: invokevirtual #6 // Method java/lang/Object.toString:()Ljava/lang/String;
28: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
31: iinc 4, 1
34: goto 8
37: return

void doLoop2_2(java.lang.Object[]);
Code:
0: iconst_0
1: istore_2
2: iload_2
3: aload_1
4: arraylength
5: if_icmpge 26
8: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: iload_2
13: aaload
14: invokevirtual #6 // Method java/lang/Object.toString:()Ljava/lang/String;
17: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: iinc 2, 1
23: goto 2
26: return

void doLoop2_3(java.lang.Object[]);
Code:
0: aload_1
1: arraylength
2: iconst_1
3: isub
4: istore_2
5: iload_2
6: iflt 27
9: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_1
13: iload_2
14: aaload
15: invokevirtual #6 // Method java/lang/Object.toString:()Ljava/lang/String;
18: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
21: iinc 2, -1
24: goto 5
27: return
}
[/code]

Failed assumptions:

  • RandomAccessList didn’t help, thus it’s still preferable to prefer interfaces
  • foreach loop for Object[] doesn’t match manual iteration, so there is still reasons to do it your way

References:
Nuances of the Java 5.0 for-each Loop
Kari’s World: Premature Optimization: Chapter “Class is the root of all evil”

/ java

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *

This site uses Akismet to reduce spam. Learn how your comment data is processed.