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)
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:
System.currentTimeMillis()
which is generally a bad idea for benchmarking; System.nanoTime()
is preferred for measuring elapsed timesYou might want to look at a microbenchmarking framework designed to avoid this sort of problem, like Caliper or JMH.
See more on this question at Stackoverflow