Suppose I have a simple interface representing a complex number, whose instances would be immutable. For the sake of brevity, I omitted the obvious plus, minus, times and divide methods that would simply create and return a new immutable instance.
public interface Complex { double real(); double imaginary(); double absolute(); double angle(); } Now the question is, what would the best way to implement this as an immutable class? The most simple and straightforward "I care about performance only when it's a problem" approach would be to store the real and imaginary parts as final fields and compute the absolute value and angle on every invocation of those methods. This keeps the class small and simple, but obviously the last two methods return the same result every time.
public final class NonCachingComplex implements Complex { private final double real; private final double imaginary; public NonCachingComplex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } @Override public double real() { return real; } @Override public double imaginary() { return imaginary; } @Override public double absolute() { return Math.sqrt((real * real) + (imaginary * imaginary)); } @Override public double angle() { return absolute() == 0 ? 0 : (Math.acos(real / absolute()) * Math.signum(imaginary)); } } So why not save the absolute value and angle into a field upon creation? Well, obviously the memory footprint of the class is now a bit larger and also, counting the the results for every instance created may be also contra productive if these two methods are called seldom.
public final class EagerCachingComplex implements Complex { private final double real; private final double imaginary; private final double absolute; private final double angle; public EagerCachingComplex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; this.absolute = Math.sqrt((real * real) + (imaginary * imaginary)); this.angle = absolute == 0 ? 0 : (Math.acos(real / absolute()) * Math.signum(imaginary)); } // real() and imaginary() stay the same... @Override public double absolute() { return absolute; } @Override public double angle() { return angle; } } A third possibility I came up with is to compute the absolute value and angle lazily, on the first time they are required. But as you can see, this makes the code a bit cluttered and error prone. Also, I'm not sure if the use of volatile modifier is actually correct in this context.
public final class LazyCachingComplex implements Complex { private final double real; private final double imaginary; private volatile Double absolute; private volatile Double angle; public LazyCachingComplex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } // real() and imaginary() stay the same... @Override public double absolute() { if (absolute == null) { absolute = Math.sqrt((real * real) + (imaginary * imaginary)); } return absolute; } @Override public double angle() { if (angle == null) { angle = absolute() == 0 ? 0 : (Math.acos(real / absolute()) * Math.signum(imaginary)); } return angle; } } So my question is, which of these three approaches is the best? Is there some other even better approach? Should I care about performance at all and stay with the first approach and think about optimizations only when performance becomes a real problem?