Reputation: 1676
Why I'm asking:
I wanted to know it there is any optimization going on at the compiler side that would make one or the other method to return preferable. Since I have read this post that python does not optimize the method to run faster.
The example:
I've declared 2 methods that deliver the same value. But barA
returns it via an internal field declaration.
public class Foo {
public int barA(){
int a = 1;
return a;
}
public int barB(){
return 1;
}
}
The tests:
public class TestFoo {
Foo foo = new Foo();
Method methodA = foo.getClass().getMethod("barA");
Method methodB = foo.getClass().getMethod("barB");
public TestFoo() throws NoSuchMethodException {
}
@Test
public void methodA() throws Exception {
assertTrue(Integer.TYPE.equals(methodA.getReturnType()));
}
@Test
public void methodB() throws Exception {
assertTrue(Integer.TYPE.equals(methodB.getReturnType()));
}
@Test
public void equalsSame() throws Exception{
assertEquals(foo.barA(), foo.barB());
}
}
The results:
The tests showed that I'm in fact dealing with the same value and return type in both methods.
Disclaimer: This picture is not meant to highlight the stop watch, junit runs for each method, as it's in no way linked to the compiler optimization I'm asking about.
The question:
Does Java actually try to optimize away "useless" field declarations in order to execute faster?
I was not able to find a question addressing this.
Using:
Upvotes: 4
Views: 856
Reputation: 140553
Given the updates by the OP, the real answer here is very basic: java is a statically compiled language.
The signature of a method ... is what the signature says. The signature says to return a int value. And that is what any method with int on its signature will return. Nothing in the Java architecture allows you to dynamically change such things at runtime. From that point of view, your tests for the return type are all bogus. The language design implies that the answer is always "the method returns int
. And please note: if the return type would be a reference type, say Number
, then of course you could have one method return an instance of Long, and another one an Integer object (resulting in different types, but still subtypes of Number)!
Beyond that, the OP talks about looking at the different execution times.
Yes, junit runs a stop watch to roughly tell you how long each test runs. But that is not measuring. In order to understand the true performance impacts of code, you have to do real measurement. From that point of view: the numbers from JUnit don't mean what you think they mean. They are not a suitable base to draw such conclusions from.
See How do I write a correct micro-benchmark in Java? for further guidance on how one could get to more meaningful numbers.
Upvotes: 2
Reputation: 44210
If we take the example:
class Main {
int foo() {
int i = 0;
return i;
}
int bar() {
return 0;
}
public static void main(String[] args) {
new Main().foo();
new Main().bar();
}
}
And view the bytecode:
class my.pckage.Main extends java.lang.Object{
my.pckage.Main();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
int foo();
Code:
0: iconst_0 //push zero onto the stack
1: istore_1 //pop off the stack and store in local variable
2: iload_1 //load an int value from local variable 1
3: ireturn //return an integer from a method
int bar();
Code:
0: iconst_0
1: ireturn
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: new #2; //class my/pckage/Main
3: dup
4: invokespecial #3; //Method "<init>":()V
7: invokevirtual #4; //Method foo:()I
10: pop
11: new #2; //class my/pckage/Main
14: dup
15: invokespecial #3; //Method "<init>":()V
18: invokevirtual #5; //Method bar:()I
21: pop
22: return
}
You can see that it's not being optimised away at this level.
As to whether the JIT compiler decides to optimise this at runtime will depend on the specific platform being targeted.
Upvotes: 3