Search code examples
javaautoboxingoptimization

How does Java decide which operator in a math expression has to be (un)boxed?


I'm currently working on my Bachelor Thesis about how to write effective Java code. The following four code snippets are part of a JMH benchmark which will execute every method 1 million times each.

public final static int primitiveOnly(int dummy, int add1, int add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}
public final static int primitiveToWrapper(int dummy, int add1, Integer add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}
public final static int wrapperToPrimitive(Integer dummy, Integer add1, int add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}
public final static Integer wrapperToWrapper(Integer dummy, Integer add1, Integer add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}

The results for this four methods are:

  • primitiveOnly: 1.7 ms/operation
  • primitiveToWrapper: 2.2 ms/operation
  • wrapperToPrimitive: 47.5 ms/operation
  • wrapperToWrapper: 48.2 ms/operation

The reason for this behaviour would be that during the operation in primitiveToWrapper the Integer value has just to be unboxed where in the operation in wrapperToPrimitive has to box the first operand into an Integer which results in an expensive object creation.

Is there a specific reason Java behaves like this? I read through the The Java Language Specification but wasn't able to find a answer to this question.

UPDATE:

To address the point regarding the return values (thanks to Phil Anderson) i updated my code. In addition i changed all the Integer variables in the benchmark class to int. This is the new version:

public final static int primitiveOnly(int dummy, int add1, int add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}

public final static int primitiveToWrapperIntDummy(int dummy, int add1, Integer add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}

public final static Integer primitiveToWrapperIntegerDummy(Integer dummy, int add1, Integer add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}

public final static int wrapperToPrimitiveIntDummy(int dummy, Integer add1, int add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}

public final static Integer wrapperToPrimitiveIntegerDummy(Integer dummy, Integer add1, int add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}

public final static int wrapperToWrapperIntDummy(int dummy, Integer add1, Integer add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}

public final static Integer wrapperToWrapperIntegerDummy(Integer dummy, Integer add1, Integer add2) {
    for(int i = 0; i < 10; i++) {
        dummy += (add1 + add2);
    }
    return dummy;
}

The results are an average of 10 iterations (1 iteration = 1 million executions of each method above).

  • primitiveOnly: 0.783
  • primitiveToWrapper (int dummy): 0.735
  • primitiveToWrapper (Integer dummy): 24.999
  • WrapperToPrimitive (int dummy): 0.709
  • WrapperToPrimitive (Integer dummy): 26.782
  • WrapperToWrapper (int dummy): 0.764
  • WrapperToWrapper (Integer dummy): 27.301

The final results now feel much more intuitive. Thanks everyone for helping me out.


Solution

  • In the second bit of code, every time you assign a value to dummy java has to box it into an Integer because that's the type of the varaible. It doesn't know that you never actually call any methods on it and that it could be a simple int.

    So each time it hits the code dummy += (add1 + add2); it has to do the following.

    • Unbox dummy
    • Perform the additions
    • Box the result back into dummy

    It will do this each time through the for loop.