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.
Related
I noticed that in the jdk source code and more specifically in the collections framework there is a preference in assigning variables right before reading them in expressions. Is it just a simple preference or is it something more important which I am not aware of? One reason that I can think of is that the variable is used in this expression only.
As I am not used to this style I find it hard to read it. The code is very condensed. Below you can see an example taken from java.util.HashMap.getNode()
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 && ...) {
...
}
As already mentioned in the comment: Doug Lea, who is one of the main authors of the collections framework and the concurrency packages, tends to do optimizations that may look confusing (or even counterintuitive) for mere mortals.
A "famous" example here is copying fields to local variables in order to minimize the size of the bytecode, which is actually also done with the table field and the local tab variable in the example that you referred to!
For very simple tests, it does not seem to make a difference (referring to the resulting bytecode size) whether the accesses are "inlined" or not. So I tried to create an example that roughly resembles the structures of the getNode method that you mentioned: An access to a field that is an array, a length check, an access to a field of one array element...
The testSeparate method does separate assignments and checks
The testInlined method uses the assignment-in-if-style
The testRepeated method (as a counterexample) does every access repeatedly
The code:
class Node
{
int k;
int j;
}
public class AssignAndUseTestComplex
{
public static void main(String[] args)
{
AssignAndUseTestComplex t = new AssignAndUseTestComplex();
t.testSeparate(1);
t.testInlined(1);
t.testRepeated(1);
}
private Node table[] = new Node[] { new Node() };
int testSeparate(int value)
{
Node[] tab = table;
if (tab != null)
{
int n = tab.length;
if (n > 0)
{
Node first = tab[(n-1)];
if (first != null)
{
return first.k+first.j;
}
}
}
return 0;
}
int testInlined(int value)
{
Node[] tab; Node first, e; int n;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1)]) != null) {
return first.k+first.j;
}
return 0;
}
int testRepeated(int value)
{
if (table != null)
{
if (table.length > 0)
{
if (table[(table.length-1)] != null)
{
return table[(table.length-1)].k+table[(table.length-1)].j;
}
}
}
return 0;
}
}
And the resulting bytecodes: The testSeparate method uses 41 instructions:
int testSeparate(int);
Code:
0: aload_0
1: getfield #15 // Field table:[Lstackoverflow/Node;
4: astore_2
5: aload_2
6: ifnull 40
9: aload_2
10: arraylength
11: istore_3
12: iload_3
13: ifle 40
16: aload_2
17: iload_3
18: iconst_1
19: isub
20: aaload
21: astore 4
23: aload 4
25: ifnull 40
28: aload 4
30: getfield #37 // Field stackoverflow/Node.k:I
33: aload 4
35: getfield #41 // Field stackoverflow/Node.j:I
38: iadd
39: ireturn
40: iconst_0
41: ireturn
The testInlined method indeed is a tad smaller, with 39 instructions
int testInlined(int);
Code:
0: aload_0
1: getfield #15 // Field table:[Lstackoverflow/Node;
4: dup
5: astore_2
6: ifnull 38
9: aload_2
10: arraylength
11: dup
12: istore 5
14: ifle 38
17: aload_2
18: iload 5
20: iconst_1
21: isub
22: aaload
23: dup
24: astore_3
25: ifnull 38
28: aload_3
29: getfield #37 // Field stackoverflow/Node.k:I
32: aload_3
33: getfield #41 // Field stackoverflow/Node.j:I
36: iadd
37: ireturn
38: iconst_0
39: ireturn
Finally, the testRepeated method uses a whopping 63 instructions
int testRepeated(int);
Code:
0: aload_0
1: getfield #15 // Field table:[Lstackoverflow/Node;
4: ifnull 62
7: aload_0
8: getfield #15 // Field table:[Lstackoverflow/Node;
11: arraylength
12: ifle 62
15: aload_0
16: getfield #15 // Field table:[Lstackoverflow/Node;
19: aload_0
20: getfield #15 // Field table:[Lstackoverflow/Node;
23: arraylength
24: iconst_1
25: isub
26: aaload
27: ifnull 62
30: aload_0
31: getfield #15 // Field table:[Lstackoverflow/Node;
34: aload_0
35: getfield #15 // Field table:[Lstackoverflow/Node;
38: arraylength
39: iconst_1
40: isub
41: aaload
42: getfield #37 // Field stackoverflow/Node.k:I
45: aload_0
46: getfield #15 // Field table:[Lstackoverflow/Node;
49: aload_0
50: getfield #15 // Field table:[Lstackoverflow/Node;
53: arraylength
54: iconst_1
55: isub
56: aaload
57: getfield #41 // Field stackoverflow/Node.j:I
60: iadd
61: ireturn
62: iconst_0
63: ireturn
So it seems that this "obscure" way of writing the queries and assignments can, indeed, save a few bytes of bytecode, and (given the justification in the linked answer about storing fields in local variables) this may have been the reason to use this style.
But...
in any case: After the method has been executed a few times, the JIT will kick in, and the resulting machine code will have "nothing" to do with the original bytecode - and I'm pretty sure that all three versions will actually be compiled to the same machine code in the end.
So the bottom line is: Don't use this style. Instead, just write dumb code that is easy to read and maintain. You'll know when it's your turn to use "optimizations" like these.
EDIT: A short addendum...
I have made a further test, and compared the testSeparate and testInlined method concerning the actual machine code that is generated by the JIT.
I modified the main method a bit, to prevent unrealistic over-optimizations or other shortcuts that the JIT might take, but the actual methods have been left unmodified.
And as expected: When calling the methods a few thousand times with a hotspot disassembly JVM and -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation -XX:+PrintAssembly, then the actual machine code of both methods is identical.
So once more, the JIT does its job pretty well, and the programmer can focus on writing readable code (whatever that means).
... and and a minor correction/clarification:
I did not test the third method, testRepeated, because it is not equivalent to the other methods (and thus, it can not result in the same machine code). This is, by the way, another small advantage of the strategy of storing fields in local variables: It offers a (very limited, but sometimes handy) form of "thread safety": It is made sure that the length of an array (like the tab array in the getNode method of HashMap) can not change while the method is being executed.
I opened My java class file in eclipse and I have a doubt in this particular line.
iconst_10
putfield Test.a : int [12]
What does [12] signify? Does it signify Bytes allocated?
My java code is
class Test {
public Integer a = 5;
public static void main(String[] args) {
Test t = new Test();
t.a = 4;//This line compiles to the above code.
}
}
This is javap code, but quite different from eclipse one
public Test();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_5
6: invokestatic #12; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
9: putfield #18; //Field a:Ljava/lang/Integer;
12: return
public static void main(java.lang.String[]);
Code:
0: new #1; //class Test
3: dup
4: invokespecial #26; //Method "<init>":()V
7: astore_1
8: aload_1
9: iconst_4
10: invokestatic #12; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
13: putfield #18; //Field a:Ljava/lang/Integer;
16: return
}
It is not bytes allocated. It is most likely the index into the constant pool for the field Test.a.
In bytecode, the putfield opcode is followed by a 16-bit unsigned
integer index. This is the index of an entry in the constant pool of
the current class.
More info: here
Referring Wikipedia
putfield
set field to value in an object objectref, where the field is
identified by a field reference index in constant pool (indexbyte1 <<
8 + indexbyte2)
IBM Java Bytecode: This link explains with an example how putfield works
The putfield opcode pops the two top values off the stack and stores a
reference to strName into the instance data name of the object
referenced by this .
public Employee(String strName, int num)
{
name = strName;
idNumber = num;
storeData(strName, num);
}
Method Employee(java.lang.String,int)
0 aload_0
1 invokespecial #3 <Method java.lang.Object()>
4 aload_0
5 aload_1
6 putfield #5 <Field java.lang.String name>
9 aload_0
10 iload_2
11 putfield #4 <Field int idNumber>
14 aload_0
15 aload_1
16 iload_2
17 invokespecial #6 <Method void storeData(java.lang.String, int)>
20 return
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.
I was wondering would there be a performance differences while i use logical operators instead of several if statements. I saw a nice link, does this apply to java also?
I just created class like
class Test{
static java.util.Random r=new java.util.Random();
boolean test(){
return r.nextBoolean();
}
void test1(){
if (test() && test() && test())
System.out.println("3x yes");
}
void test2(){
if (test())
if (test())
if (test())
System.out.println("3x yes");
}
}
compiled it then decompiled by javap -c Test and got these result
class Test {
static java.util.Random r;
Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
boolean test();
Code:
0: getstatic #2 // Field r:Ljava/util/Random;
3: invokevirtual #3 // Method java/util/Random.nextBoole
an:()Z
6: ireturn
void test1();
Code:
0: aload_0
1: invokevirtual #4 // Method test:()Z
4: ifeq 29
7: aload_0
8: invokevirtual #4 // Method test:()Z
11: ifeq 29
14: aload_0
15: invokevirtual #4 // Method test:()Z
18: ifeq 29
21: getstatic #5 // Field java/lang/System.out:Ljava/
io/PrintStream;
24: ldc #6 // String 3x yes
26: invokevirtual #7 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
29: return
void test2();
Code:
0: aload_0
1: invokevirtual #4 // Method test:()Z
4: ifeq 29
7: aload_0
8: invokevirtual #4 // Method test:()Z
11: ifeq 29
14: aload_0
15: invokevirtual #4 // Method test:()Z
18: ifeq 29
21: getstatic #5 // Field java/lang/System.out:Ljava/
io/PrintStream;
24: ldc #6 // String 3x yes
26: invokevirtual #7 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
29: return
static {};
Code:
0: new #8 // class java/util/Random
3: dup
4: invokespecial #9 // Method java/util/Random."<init>":
()V
7: putstatic #2 // Field r:Ljava/util/Random;
10: return
}
As you can see bytecodes of test1 and test2 are same, so there is no difference in using
if (test() && test() && test())
or
if (test())
if (test())
if (test())
It's implementation dependent - so you'll need to benchmark to be sure.
Having said that, most JIT compilers are smart enough to optimise boolean comparisons very effectively so you are unlikely to see any difference.
The only area where logical operators are likely to offer a substantial advantage are in cases where you are using them to perform bitwise computations. This can be very efficient since it can result in branchless code that exploits hardware instructions.
Both forms compile to the same code. Contrary to the suggestions in other answers, this is not an 'optimization', and it would be astonishing if different compilers did different things. There is only one sensible way to compile && and that is by treating it the same as another 'if'. I can't even think of a non-sensible way.
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)