Personally, I don't think you can draw any meaningful conclusions from a contrived example like this.
But if you really want to know, why not use javap to decompile the code and see what's different? Why guess about what the compiler's doing when you can see for yourself without asking here?
Byte code for the first case:
public class Stackoverflow extends java.lang.Object{
public Stackoverflow();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_4
1: anewarray #2; //class java/lang/String
4: dup
5: iconst_0
6: ldc #3; //String A
8: aastore
9: dup
10: iconst_1
11: ldc #4; //String B
13: aastore
14: dup
15: iconst_2
16: ldc #5; //String C
18: aastore
19: dup
20: iconst_3
21: ldc #6; //String D
23: aastore
24: invokestatic #7; //Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List
27: astore_1
28: invokestatic #8; //Method java/lang/System.currentTimeMillis:()J
31: lstore_2
32: ldc #9; //int 1000000
34: istore 4
36: iload 4
38: aload_1
39: invokeinterface #10, 1; //InterfaceMethod java/util/List.size:()I
44: if_icmple 61
47: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
50: ldc #12; //String Hello
52: invokevirtual #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
55: iinc 4, -1
58: goto 36
61: invokestatic #8; //Method java/lang/System.currentTimeMillis:()J
64: lstore 4
66: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
69: new #14; //class java/lang/StringBuilder
72: dup
73: invokespecial #15; //Method java/lang/StringBuilder."<init>":()V
76: ldc #16; //String Finish:
78: invokevirtual #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/la
81: lload 4
83: lload_2
84: lsub
85: invokevirtual #18; //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
88: invokevirtual #19; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
91: invokevirtual #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
94: return
}
Byte code for the second case:
public class Stackoverflow extends java.lang.Object{
public Stackoverflow();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_4
1: anewarray #2; //class java/lang/String
4: dup
5: iconst_0
6: ldc #3; //String A
8: aastore
9: dup
10: iconst_1
11: ldc #4; //String B
13: aastore
14: dup
15: iconst_2
16: ldc #5; //String C
18: aastore
19: dup
20: iconst_3
21: ldc #6; //String D
23: aastore
24: invokestatic #7; //Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
27: astore_1
28: invokestatic #8; //Method java/lang/System.currentTimeMillis:()J
31: lstore_2
32: aload_1
33: invokeinterface #9, 1; //InterfaceMethod java/util/List.size:()I
38: istore 4
40: ldc #10; //int 1000000
42: istore 5
44: iload 5
46: iload 4
48: if_icmple 65
51: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
54: ldc #12; //String Hello
56: invokevirtual #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
59: iinc 5, -1
62: goto 44
65: invokestatic #8; //Method java/lang/System.currentTimeMillis:()J
68: lstore 5
70: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
73: new #14; //class java/lang/StringBuilder
76: dup
77: invokespecial #15; //Method java/lang/StringBuilder."<init>":()V
80: ldc #16; //String Finish:
82: invokevirtual #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
85: lload 5
87: lload_2
88: lsub
89: invokevirtual #18; //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
92: invokevirtual #19; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
95: invokevirtual #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
98: return
}
There are differences, but I'm not sure I can make a definitive statement about their effect on performance.
I'd code the second one, because it would mean (on the face of it) one method call as opposed to one per loop iteration. I don't know if the compiler can optimize it away, but I'm certain that I can do it pretty easily. So I do, regardless of its effect on wall time.