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?
In object-oriented and functional programming, an immutable object (unchangeable object) is an object whose state cannot be modified after it is created. This is in contrast to a mutable object (changeable object), which can be modified after it is created.
Immutable objects are useful in multithreaded applications because they can be safely accessed by several threads concurrently, without the need for locking or other synchronization.
We can not change anything once the object is created. For example, primitive objects such as int, long, float, double, all legacy classes, Wrapper class, String class, etc. In a nutshell, immutable means unmodified or unchangeable. Once the immutable objects are created, its object values and state can not be changed.
Immutable data is a piece of information in a database that cannot be (or shouldn't be) deleted or modified. Most traditional databases store data in a mutable format, meaning the database overwrites the older data when new data is available.
I'd go for NonCachingComplex pretty much every time.
Reasons:
Of the others, LazyCachingComplex is particularly bad, since it is using boxed values for absolute and angle (which implies an extra memory dereference to access, plus two extra lots of object overhead). I think it unlikely that would ever see a performance benefit from doing this.
Note that if you really care about performance then you wouldn't use a Complex interface either - the best performance is from directly making a final Complex class, and referring to this class directly in your code. Method invocations via an interface are (slightly) more costly than method invocations on a final class.
I'm sure it isn't the answer you are looking for, but I would say it depends ;)
I personally don't think the lazy init is bad at all. But I would weight your options against the needs of your application - is performance really a concern? Are you using the values of absolute and angle multiple times for the same object? Is the computation of those fields really that slow?
My rule of thumb is generally to keep the code as clean (minimal) as possible and only add complexity when it is shown that it is required. I would stick with your NonCaching version until then.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With