Search code examples
javaperformancefinal

Java performance in creating objects


I'm trying to improve my knowledge in Java performance optimization and I tried multiple approach to create an object.
I came across this behaviour I'm not familiar with regarding usage of final members in a class: the creation of an object is far less expensive (in terms of time) if the members are not final. Is it correct or is there some floaws in my code?

The object with not final members:

public class ComplexNumber {
    private double re, im;

    public ComplexNumber(double _re, double _im) {
        re = _re;
        im = _im;
    }

    public void setRe (double _re) {
        re = _re;
    }

    public void setIm (double _im) {
        im = _im;
    }

    @Override
    public String toString() {
        return re + " + i" + im;
    }

    @Override
    public int hashCode() {
        return 47 + 31*(int)re + 31*(int)im;
    }
}  

The object with final members:

public class FinalComplexNumber {
    private final double re, im;

    public FinalComplexNumber(double _re, double _im) {
        re = _re;
        im = _im;
    }

    @Override
    public String toString() {
        return re + " + i" + im;
    }

    @Override
    public int hashCode() {
        return 47 + 31*(int)re + 31*(int)im;
    }
}  

The main class

public class PerformanceTest {

    private static final long ITERATIONS = 100000000l;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {


        ComplexNumber nr = new ComplexNumber(0, 0);
        System.out.println(nr);

        long time = System.currentTimeMillis();
        for (int i = 0; i < ITERATIONS; i++) {
            ComplexNumber num = new ComplexNumber(i, i);
        }
        System.out.println(System.currentTimeMillis() - time);

        time = System.currentTimeMillis();
        for (int i = 0; i < ITERATIONS; i++) {
            nr.setIm(i);
            nr.setRe(i);
        }
        System.out.println(System.currentTimeMillis() - time);

        time = System.currentTimeMillis();
        for (int i = 0; i < ITERATIONS; i++) {
            FinalComplexNumber num = new FinalComplexNumber(i, i);
        }
        System.out.println(System.currentTimeMillis() - time);
    }
}  

The results:

run:
0.0 + i0.0
953
219
7875
BUILD SUCCESSFUL (total time: 9 seconds)

Solution

  • the creation of an object is far less expensive (in terms of time) if the members are not final.

    No, that's absolutely not the case. Basically, your approach to benchmarking is broken:

    • You're using System.currentTimeMillis() which is generally a bad idea for benchmarking; System.nanoTime() is preferred for measuring elapsed times
    • You're not providing any JIT warmup
    • You're not using the objects you create, which may allow JIT optimizations which would be invalid in more normal code
    • You're not even trying to start with a level playing-field in terms of in-memory garbage, so you may well find that your first loop doesn't need to perform any garbage collection, but your last loop does.

    You might want to look at a microbenchmarking framework designed to avoid this sort of problem, like Caliper or JMH.