blkpingu
blkpingu

Reputation: 1676

Does Java optimize away a field that's just serving as a return value?

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 tests

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

Answers (2)

GhostCat
GhostCat

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

Michael
Michael

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

Related Questions