Hello i have two samples of code
if/else if/else statements
private Object getObj(message) {
if (message
There is a third form (allowing still some variation).
return Stream.<Supplier<Object>>of(message::getA, message::getB, message::getC)
.map(Supplier::get)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
Probably the least flexible and efficient at this moment, but clear.
A couple of days ago I ran a thorough performance analysis. There's a huge performance impact. With AdoptOpenJDK, if
statements are up to 10 times faster. When the JIT compiler runs hot, this reduces to a 20% penalty.
GraalVM does a better job: 3 times slowdown with the cold JVM, and after giving the compiler enough time to do its magic, there's also a 20% performance penalty.
However, the real question is which version is better for reading and maintaining the application. If you're like me, it's easier to read the if
statement, but there are also people preferring the functional approach.
If you're ready for a deep, deep dive, I invite you to read my detailed analysis about the performance and the implementation of Optional.orElseGet()
and its friends.
Don't use Optional
s for conditional logic.
They were designed, to be returned from a method to indicate a potentially absent value.
Just because you can nicely chain them into a single line doesn't mean that it's understandable. Also you literally gain nothing. The performance overhead may be significant. In the worst case N
objects being created and then discarded. Just stay with your "normal" if-else
chains.
Instead of finding ways to make your current code more readable, take a step back and ask yourself why you need 15-20 if-else statements. Can you split some logic up? Why do you need a getter for so many different fields with potentially different types in the first place? etc.
In my opinion after around 20 years of commercial experience, I've formed a view that pursuing readability is absolute stupidity, and at the same time, intentionally writing convoluted code is evil.
I know this goes totally against popular opinion.
However, everyone needs to realize this...
if
or Optional
are more readable or not. These kinds of debates will occur irrespective of what constructs or situations we are in.if
option, which is more performant than the functional approach, each and every time, then the people reading that code will get used to it and find it MORE READABLE - because it is the style that they have now become accustomed to.So, in essence: go with the if
... do NOT use that Optional
!
If your goal is condensed code, then use ternary chaining. Performance is likely identical to that of a series of if-then-else statements.
( this.getA() != null ) ? this.getA()
: ( this.getB() != null ) ? this.getB()
: ( this.getC() != null ) ? this.getC()
: null;
As the Answer by Lino correctly states, you are trying to take Optional
beyond their original design purpose (returning values within lambdas & streams). Generally best to use Optional
only with a return
statement, and only then when you want to make clear that null is a valid value to be returned. See this Answer by Brian Goetz.
A ternary operator is a condensed if-then-else
, combined into a one-liner.
result = test ? valueToUseIfTestIsTrue : valueToUseIfTestIsFalse
Example:
Color color = isPrinterMonochrome ? Color.GREY : Color.GREEN ;
Use a chain of ternary statements.
So this:
if ( this.getA() != null )
return this.getA();
else if ( this.getB() != null )
return this.getB();
else if ( this.getC() != null )
return this.getC();
else return null;
…becomes this:
return
( this.getA() != null ) ? this.getA()
: ( this.getB() != null ) ? this.getB()
: ( this.getC() != null ) ? this.getC()
: null;
Example code.
public String getA ()
{
// return "A";
return null;
}
public String getB ()
{
// return "B";
return null;
}
public String getC ()
{
return "C";
// return null;
}
public String getABC ()
{
if ( this.getA() != null )
return this.getA();
else if ( this.getB() != null )
return this.getB();
else if ( this.getC() != null )
return this.getC();
else return null;
}
public String getABCTernary ()
{
return
( this.getA() != null ) ? this.getA()
: ( this.getB() != null ) ? this.getB()
: ( this.getC() != null ) ? this.getC()
: null;
}
Run that example code.
String s = this.getABCTernary();
System.out.println( "s: " + s );
C
how these two compare in terms of performance
The ternary operator in Java is "short-circuiting", meaning the left or right side that matches the test results is the only code called. In our code here, if getA
returns a non-null value, that value is returned immediately. The further calls to getB
and getC
are never executed. So in this regard, the performance of the chained ternary is the same as a cascading if-then-else statement: first-match wins, no further calls.
If you mean performance as in nanoseconds of execution, I do not know. Worrying about that would be falling into the trap of premature optimization. Modern JVMs are extremely well-tuned for optimizing your code.