What are the pros and cons of using this:
String a = new String();
switch (i) {
case 1: a = "Cueck"; break;
case 2: a = "Blub"; break;
case 3: a = "Writing cases is BORING!"; break;
}
System.out.println(a);
Versus:
switch (i) {
case 1: System.out.println("Cueck"); break;
case 2: System.out.println("Blub"); break;
case 3: System.out.println("Writing cases is BORING!"); break;
}
Which generates better bytecode? And which generates more bytecode?
Your first option is neater and has less redundant code. One suggested change:
String a;
switch (i) {
case 1: a = "Cueck"; break;
case 2: a = "Blub"; break;
case 3: a = "Writing cases is BORING!"; break;
default: throw new IllegalStateException("Unknown option!");
}
System.out.println(a);
Don't create a String unnecessarily - a should be instatiated when required. A default case should either throw an exception or set a to a default value.
Which generates better bytecode? And which generates more bytecode?
I wouldn't worry about that. This doesn't strike me as a likely bottleneck in any real-life application. Also, you cannot be sure what the JVM will do to optimise the byte-code once your application is running.
Using javap -c classname you can check the bytecode yourself,
Here's option 1:
(Note, I had to initialise a = null otherwise it doesn't compile)
7: aconst_null
8: astore_2
9: iload_1
10: tableswitch{ //1 to 3
1: 36;
2: 42;
3: 48;
default: 51 }
36: ldc #3; //String Cueck
38: astore_2
39: goto 51
42: ldc #4; //String Blub
44: astore_2
45: goto 51
48: ldc #5; //String Writing cases is BORING!
50: astore_2
51: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
54: aload_2
55: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
58: return
Here's option 2:
7: iload_1
8: tableswitch{ //1 to 3
1: 36;
2: 47;
3: 58;
default: 66 }
36: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
39: ldc #4; //String Cueck
41: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
44: goto 66
47: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
50: ldc #6; //String Blub
52: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
55: goto 66
58: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
61: ldc #7; //String Writing cases is BORING!
63: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
66: return
Personally, I don't think there's better bytecode in this instance, I find option 1 more readable.
I don't think there will be much difference in bytecode size but I suggest first approach. If you in some future code changes decide not to call System.out.println(a) but logger.debug(a) you will change that only on one place and not on all case switches.
Related
If I want to put something like
public int compareTo(fractions.Fraction);
Code:
0: aload_0
1: aload_1
2: invokevirtual #92 // Method minus:(Lfractions/Fraction;)Lfractions/Fraction;
5: astore_2
6: aload_2
7: getfield #1 // Field numerator:J
10: lconst_0
11: lcmp
12: ifge 17
15: iconst_m1
16: ireturn
17: aload_2
18: getfield #1 // Field numerator:J
21: lconst_0
22: lcmp
23: ifle 28
26: iconst_1
27: ireturn
28: iconst_0
29: ireturn
into a GitHub Gist, what file extension should I use for the Gist? My first instinct was *.java, but that's kind of misleading. So now I'm thinking *.javap.
I did try putting this question to Google, that doesn't seem to have gotten any useful results.
In Java, if I'm performing multiple methods on an object, I can chain them, or I can make a temporary variable, like so
Chaining
System.out.println( str.substring(0,4).substring(0,2));
Temp variable
String tmp = str.substring(0,4);
tmp = tmp.substring(0,2);
System.out.println(tmp);
Obviously, the difference is negligible in this example, but could make an impact when you're doing this over thousands of strings/some other object.
My question is, is one of these more "efficient" in terms of not making extra object allocations or filling the heap (and thus making GC get called sooner)?
I tried to compare the bytecodes of the two in a loop over a couple strings, but it looks similar, sans for the last few lines. I don't understand all the bytecode calls, so I'm not sure if any of these have to do with allocating new objects.
Compiled from "TestNoTmp.java"
public class TestNoTmp {
public TestNoTmp();
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 These
8: aastore
9: dup
10: iconst_1
11: ldc #4 // String Are__
13: aastore
14: dup
15: iconst_2
16: ldc #5 // String Some_
18: aastore
19: dup
20: iconst_3
21: ldc #6 // String Strings
23: aastore
24: astore_1
25: aload_1
26: astore_2
27: aload_2
28: arraylength
29: istore_3
30: iconst_0
31: istore 4
33: iload 4
35: iload_3
36: if_icmpge 69
39: aload_2
40: iload 4
42: aaload
43: astore 5
45: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
48: aload 5
50: iconst_0
51: iconst_4
52: invokevirtual #8 // Method java/lang/String.substring:(II)Ljava/lang/String;
55: iconst_0
56: iconst_2
57: invokevirtual #8 // Method java/lang/String.substring:(II)Ljava/lang/String;
60: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
63: iinc 4, 1
66: goto 33
69: return
}
public class TestTmp {
public TestTmp();
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 These
8: aastore
9: dup
10: iconst_1
11: ldc #4 // String Are__
13: aastore
14: dup
15: iconst_2
16: ldc #5 // String Some_
18: aastore
19: dup
20: iconst_3
21: ldc #6 // String Strings
23: aastore
24: astore_1
25: aload_1
26: astore_2
27: aload_2
28: arraylength
29: istore_3
30: iconst_0
31: istore 4
33: iload 4
35: iload_3
36: if_icmpge 77
39: aload_2
40: iload 4
42: aaload
43: astore 5
45: aload 5
47: iconst_0
48: iconst_4
49: invokevirtual #7 // Method java/lang/String.substring:(II)Ljava/lang/String;
52: astore 6
54: aload 6
56: iconst_0
57: iconst_2
58: invokevirtual #7 // Method java/lang/String.substring:(II)Ljava/lang/String;
61: astore 6
63: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
66: aload 6
68: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
71: iinc 4, 1
74: goto 33
77: return
}
In your example, you're working with Strings, which are immutable. In your code:
str.substring(0,4).substring(0,2)
the first call to substring must generate a new String object because str cannot be modified. Similarly, the second call to substring on that new String object will create another new String object.
The difference in bytecodes is simply a result of the order in which the compiler calls methods. In the TestTmp case, all the string manipulation occurs before the call to PrintStream. For TestNoTmp, the String calls happen within the PrintStream call, which is very logical when you look at the code.
To answer your question, this will make no difference in terms of object allocation and therefore GC impact.
Which one is faster, Foo.b or Foo.c?
public class Foo{
int a = 0;
public int b(){
if(a == 0){
return a = 1;
}
return a;
}
public int c(){
if(a == 0){
a = 1;
}
return a;
}
}
Disassembled byte codes:
public int b();
Code:
0: aload_0
1: getfield #2 // Field a:I
4: ifne 14
7: aload_0
8: iconst_1
9: dup_x1
10: putfield #2 // Field a:I
13: ireturn
14: aload_0
15: getfield #2 // Field a:I
18: ireturn
public int c();
Code:
0: aload_0
1: getfield #2 // Field a:I
4: ifne 12
7: aload_0
8: iconst_1
9: putfield #2 // Field a:I
12: aload_0
13: getfield #2 // Field a:I
16: ireturn
}
It seems that Foo.c() has an extra getfield, but Foo.b() also has extra operations.
The differences on the bytecode level are in the if-block
7: aload_0 "Start of if {"
8: iconst_1
9: dup_x1
10: putfield #2
13: ireturn "End of if } and method execution"
7: aload_0 "Start of if {"
8: iconst_1
9: putfield #2"End of if }, but not end of execution"
The amount of operations executed is still the same, no matter which branch is taken so the only difference is some "wasted" bytecodes. In a real world situation this is not a performance issue, but rather a code style issue.
Unless you are calling this code in a loop iterating millions of times, then the difference between the two approaches is only academic, and is highly unlikely to impact the overall performance of your system compared with operations that are significantly more costly, like disk or network i/o.
I have a small program testing literals behaviour in Java.
public static void main(String[] args) {
String a = "foo";
String b = "foo";
String c = new String("foo");
System.out.println(a == b);
System.out.println(a.intern() == b);
System.out.println(a.intern() == a);
System.out.println(a == c);
System.out.println(c == b);
}
The results are:
true
true
true
false
false
The bytecode (javap -c MyClass)
public MyClass();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String foo
2: astore_1
3: ldc #2; //String foo
5: astore_2
6: new #3; //class java/lang/String
9: dup
10: ldc #2; //String foo
12: invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: aload_2
21: if_acmpne 28
24: iconst_1
25: goto 29
28: iconst_0
29: invokevirtual #6; //Method java/io/PrintStream.println:(Z)V
32: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
35: aload_1
36: invokevirtual #7; //Method java/lang/String.intern:()Ljava/lang/String;
39: aload_2
40: if_acmpne 47
43: iconst_1
44: goto 48
47: iconst_0
48: invokevirtual #6; //Method java/io/PrintStream.println:(Z)V
51: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
54: aload_1
55: invokevirtual #7; //Method java/lang/String.intern:()Ljava/lang/String;
58: aload_1
59: if_acmpne 66
62: iconst_1
63: goto 67
66: iconst_0
67: invokevirtual #6; //Method java/io/PrintStream.println:(Z)V
70: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
73: aload_1
74: aload_3
75: if_acmpne 82
78: iconst_1
79: goto 83
82: iconst_0
83: invokevirtual #6; //Method java/io/PrintStream.println:(Z)V
86: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
89: aload_3
90: aload_2
91: if_acmpne 98
94: iconst_1
95: goto 99
98: iconst_0
99: invokevirtual #6; //Method java/io/PrintStream.println:(Z)V
102: return
}
Questions)
1) I see that system.out.println confirms, that a and b are the same objects
What are the difference between:
System.out.println(a == b);
System.out.println(a.intern() == b);
2) Is the String optimalization is working becaouse JVM puts the same String literals in NonHeap-PermanentGeneration-InternedStrings? Is that why InternedString were created? Then why even without a.intern() this is equal: a==b
What are the difference between: System.out.println(a == b); System.out.println(a.intern() == b);
Only that the second involves an entirely unnecessary method call.
Is the String optimalization is working becaouse JVM puts the same String literals in NonHeap-PermanentGeneration-InternedStrings? Is that why InternedString were created? Then why even without a.intern() this is equal: a==b
Because the compiler and JVM work together to automatically intern string literals. The compiler puts them in a section of the class file calls the "constant pool," and the JVM loads those constants into the intern pool when the class is loaded.
Just for clarity for casual readers: The correct way to compare strings in Java is to use the .equals method or similar, not ==. Using == with string instances is usually incorrect. The OP is presumably using it here in an effort to understand how and when strings are interned; in real code, you wouldn't. (Similarly: new String("foo") is almost always at best unnecessary, and more likely actively a bad idea. Again unless you're playing around with when and how strings are interned.)
Say i have the following line in my program:
jobSetupErrors.append("abc");
In the case above where jobSetupErrors is a StringBuilder(), what i see happen is:
New String Object is created and assigned value "abc"
value of that String object is assigned to the existing StringBuilder object
If that is correct, and I add 1 more line ...
jobSetupErrors.append("abc");
logger.info("abc");
In the above example are we creating String object separately 2 times?
If so, would it be more proper to do something like this?
String a = "abc";
jobSetupErrors.append(a);
logger.info(a);
Is this a better approach? Please advise
In the above example are we creating
String object separately 2 times?
No, because in Java String literals (anything in double-quotes) are interned. What this means is that both of those lines are referring to the same String, so no further optimization is necessary.
In your second example, you are only creating an extra reference to the same String, but this is what Java has already done for you by placing a reference to it in something called the string pool. This happens the first time it sees "abc"; the second time, it checks the pool and finds that "abc" already exists, so it is replaced with the same reference as the first one.
See http://en.wikipedia.org/wiki/String_interning for more information on String interning.
To help find out, I wrote a class like the following:
class Test {
String a = "abc" ;
StringBuilder buffer = new StringBuilder() ;
public void normal() {
buffer.append( "abc" ) ;
buffer.append( "abc" ) ;
}
public void clever() {
buffer.append( a ) ;
buffer.append( a ) ;
}
}
If we compile this, and then run javap over it to extract the bytecode:
14:09:58 :: javap $ javap -c Test
Compiled from "Test.java"
class Test extends java.lang.Object{
java.lang.String a;
java.lang.StringBuilder buffer;
Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2; //String abc
7: putfield #3; //Field a:Ljava/lang/String;
10: aload_0
11: new #4; //class java/lang/StringBuilder
14: dup
15: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
18: putfield #6; //Field buffer:Ljava/lang/StringBuilder;
21: return
public void normal();
Code:
0: aload_0
1: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
4: ldc #2; //String abc
6: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
9: pop
10: aload_0
11: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
14: ldc #2; //String abc
16: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: pop
20: return
public void clever();
Code:
0: aload_0
1: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
4: aload_0
5: getfield #3; //Field a:Ljava/lang/String;
8: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: pop
12: aload_0
13: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
16: aload_0
17: getfield #3; //Field a:Ljava/lang/String;
20: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: pop
24: return
}
We can see 2 things.
First, the normal method is using the same String instance for both of those calls (indeed it is the same literal as is set to the a member variable of this class in the initialisation block)
And secondly, the clever method is longer than the normal one. This is because extra steps are required to fetch the property out of the class.
So the moral of the story is that 99% of the time, Java does things the right way on it's own, and theres no need in trying to be clever ;-) (and javap is a really cool tool for when you want to know exactly what's going on)