Optional vs if/else-if performance java 8 - java

Hello i have two samples of code
if/else if/else statements
private Object getObj(message) {
if (message.getA() != null)
return message.getA();
else if (message.getB() != null)
return message.getB();
else if (message.getC() != null)
return message.getC();
else return null;
}
Optional statements
private Optional<Object> wrap(Object o){
return Optional.ofNullable(o);
}
private Object getObj(message) {
return wrap(message.getA())
.orElseGet(() -> wrap(message.getB())
.orElseGet(() -> wrap(message.getC())
.orElse(null)));
}
So my question is how these two compare in terms of performance (i have about 15-20 if-else statements on actual code)?
Is it worth refactoring the code readability vs performance or is a misusage of optionals?
Also what is the performance penalty in case the if/else-if statements grown to 100+?
Thanks in advance

Don't use Optionals 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.

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.

tl;dr
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;
Ternary chaining
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
Pros and cons
The upside to the ternary chain is condensed code, collapsed into a one-liner.
The downside is that you are calling your getter method twice in this particular situation just to get a single value. Not a problem for a simple fetch-the-variable kind of getter, but impact performance if the getter is a time-consuming method such as a remote web services call. And, the cascading if-then-else has the same problem, also calling your getter twice.
Performance
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.

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...
What is readable to one person is not necessarily readable to the next. Even in this thread, we have varying opinions of whether if or Optional are more readable or not. These kinds of debates will occur irrespective of what constructs or situations we are in.
If we take the 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.
Performant code does not have to be "hard to read"... but this loops back to points 1 and 2. It's a matter for developers to actually know the fundamentals of the language they are using, and writing the code appropriate for that language, rather than trying to form "english sentences" in their code.
So, in essence: go with the if... do NOT use that Optional!

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.

Related

Reducing conditions within a if statement

I have a code snippet as below. Here there is a nested if else loop as well as multiple conditions [all different parameters]. What is the best way to optimize this.
if(request!=null && !StringUtils.isBlank(request)) {
if(request.getFirstName()!=null && !StringUtils.isBlank(request.getFirstName())
&& request.getLastName()!=null && !StringUtils.isBlank(request.getLastName())
&& request.getAge()!=null && !StringUtils.isBlank(request.getAge())
&& request.getAddress()!=null && !StringUtils.isBlank(request.getAddress())
&& request.getPhoneNumber()!=null && !StringUtils.isBlank(request.getPhoneNumber())) {
return true;
}else {
return false;
}
}else {
return false;
}
I had thought of using switch case and for loop as well but all the conditions are based on different variables, I didn't see it as compatible.
StringUtils from commons-lang already has a method which accepts an array of Strings. It will check for null or empty or blank strings. So all your checks boil down to:
return !(request == null || StringUtils.isAnyBlank(
request.getFirstName, request.getLastName,
request.getAge, request.getPhoneNumber));
You can try StringUtils.isAnyBlank(). Please refer attached link.
isAnyBlank : https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#isAnyBlank-java.lang.CharSequence
If you don't use commons-lang dependency you can simply use Stream API (Java 8+)
Boolean allNonBlank = Stream.of(
request.getFirstName(),
request.getLastName(),
request.getAge(),
request.getPhoneNumber())
.allMatch(it -> it != null && !String.isBlank(it));
You have a few syntax errors
You are passing request to StringUtils but it doesn't appear to implement CharSequence
You are using !! instead of !
You invocation of the get methods does not include the () to mark it as methods.
Although not an error, you do not need nested if-statements here. Using unnecessary if-else-blocks can make it harder to decipher what the code is doing. It can, however, allow for comments to describe why certain conditions are being checked or whatever. None of that seems relevant here. In fact, you can pass the result of the boolean operation without any if-statement. Using if-statements that return true or false looks like this.
if (<condition-is-true?>) return true
else return false;
Which can be simplified to...
return <condition-is-true?>;
Further, assuming you are using using Apache StringUtils, you do not need to check for null first - the isEmpty(CharSequence) method does that. Additionally, StringUtils includes the isAnyEmpty(CharSequence...) method so you can pass all of the Strings at once.
return request != null && !StringUtils.isAnyEmpty(
request.getFirstName(),
request.getLastName(),
request.getAge(),
request.getAddress(),
request.getPhoneNumber());

Efficient null check for a compound object in Java [duplicate]

This question already has answers here:
is there a Java equivalent to null coalescing operator (??) in C#? [duplicate]
(5 answers)
Null check chain vs catching NullPointerException
(19 answers)
Closed 6 years ago.
A program creates a JDialog panel with multiple tabs. One of the tabs has several tables. A JTable has adjustable column width. This tab is generated under different conditions. Sometimes from the state tab is null, sometimes tab exists, but the table is null. Sometimes user haven't resized the column yet.
I am looking for a method to save the columnWidth value if user resized the column. Checking for null seems bulky in this situation:
jpanel.tab.table.width
the best method I can find is:
if( jpanel!=null &&
jpanel.jtab!=null &&
jpanel.jtab.jtable!=null && ...
Is there a better way to do this null check?
I saw this question:
is there a Java equivalent to null coalescing operator (??) in C#?
It doesn't list a solution and is quite old (Java 6-7 time). I was hoping this feature was added in later releases.
There's no way to do exactly what you want.
However, you can just throw everything into a try statement:
try {
myItem = bundle.category.subcategory.item;
}
catch(NullpointerException ignored) {}
Note that this looks very hacked, and it's rather poor coding practice. Your current solution is probably the best approach in terms of clarity.
Edit: I tried posting another Anwser but the button is greyed out, so I'll put it here:
Feels like repeating same code many times, when you should use a for loop
You can indeed use a for loop, but that will invovle Reflection and much boilerplate code. Imagine something like this:
static boolean checkDeepNull(Object root, String... attributes) throws NoSuchFieldException, IllegalAccessException {
Object currentAttribute = root;
for(int attr = 0; currentAttribute != null && attr < attributes.length; attr++){
Field nextField = currentAttribute.getClass().getField(attributes[attr]);
Object nextAttribute = nextField.get(current);
if(nextAttribute == null) return false;
currentAttribute = nextAttribute;
}
return true;
}
How to use it: if(checkDeepNull(bundle, "category", "subcategory", "item"))
You could have an interface which determines nullability:
public interface Nullability {
public boolean hasNulls();
}
And then simply have the parent call any children like so:
public boolean hasNulls() {
return this.bundle == null || bundle.hasNulls();
}
//in bundle
public boolean hasNulls() {
return this.category == null || category.hasNulls();
}
Regardless, if you have to nullcheck everything, you're going to be doing a lot of boilerplate code if you don't provide a means of iteration. That's what you should really focus on.
On a personal level, I disagree heavily with exposing fields like that. It's a very easy way to lead to more headaches and errors in design.
The short answer is no.
Can you redesign bundle so that it is always fully constructed? I.e., if bundle != null, then category, subcategory and item always exist? This could also help with concurrency issues. Basically, if nulls give you problems, where possible, don't allow these fields to be null.
Another option is the Null Object Pattern. Basically, you have a "default" implementation of Bundle which always return getCategory() that always returns a value for getSubcategory(), but ultimately the call to getItem() returns null or something to indicate "nothing". This is a great pattern but requires some work.
I hesitate to suggest it, but it is rare for any of the items to be null, at some point it may be faster and clearer to just catch the NPE, but this style should really be avoided. And it is a definite code smell that your design is poor. Avoid it if at all possible.
try {
return foo.bar.bap.zaz.blah.blah;
}
catch (NullPointerException ignored) {
return null;
}

Cyclomatic Complexity, joining conditions and readability

Consider the following method (in Java - and please just ignore the content):
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null) {
return false;
}
if (getClass() != object.getClass()) {
return false;
}
if (hashCode() != object.hashCode()) {
return false;
}
return true;
}
I have some plugin that calculates: eV(g)=5 and V(g)=5 - that is, it calculates Essential and common CC.
Now, we can write the above method as:
public boolean equals2(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
return hashCode() == object.hashCode();
}
and this plugin calculates eV(g)=3 and V(g)=3.
But how I do understand CC, the values should be the same! CC is not about counting the lines of code, but the independent paths. Therefore, joining two if in one line does not really reduces CC. In fact, it only can make things less readable.
Am I right?
EDIT
Forgot to share this small convenient table for calculating CC quickly: Start with a initial (default) value of one (1). Add one (1) for each occurrence of each of the following:
if statement
while statement
for statement
case statement
catch statement
&& and || boolean operations
?: ternary operator and ?: Elvis operator.
?. null-check operator
EDIT 2
I proved that my plugin is not working well, since when I inline everything in one line:
public boolean equals(Object object) {
return this == object || object != null && getClass() == object.getClass() && hashCode() == object.hashCode();
}
it returns CC == 1, which is clearly wrong. Anyway, the question remains: is CC reduced
[A] 5 -> 4, or
[B] 4 -> 3
?
Long story short...
Your approach is a good approach to calculate CC, you just need to decide what you really want to do with it, and modify accordingly, if you need so.
For your second example, both CC=3 and CC=5 seem to be good.
The long story...
There are many different ways to calculate CC. You need to decide what is your purpose, and you need to know what are the limitations of your analysis.
The original definition from McCabe is actually the cyclomatic complexity (from graph theory) of the control flow graph. To calculate that one, you need to have a control flow graph, which might require a more precise analysis than your current one.
Static analyzers want to calculate metrics fast, so they do not analyze the control flow, but they calculate a complexity metric that is, say, close to it. As a result, there are several approaches...
For example, you can read a discussion about the CC metric of SonarQube here or another example how SourceMeter calculates McCC here.
What is common, that these tools count conditional statements, just like you do.
But, these metrics wont be always equal with the number of independent execution paths... at least, they give a good estimation.
Two different ways to calculate CC (McCabe and Myers' extension):
V_l(g) = number of decision nodes + 1
V_2(g) = number of simple_predicates in decision nodes + 1
If your goal is to estimate the number of test cases, V2 is the one for you. But, if you want to have a measure for code comprehension (e.g. you want to identify methods that are hard to maintain and should be simplified in the code), V1 is easier to calculate and enough for you.
In addition, static analyzers measure a number of additional complexity metrics too (e.g. Nesting Level).
Converting this
if (hashCode() != object.hashCode()) {
return false;
}
return true;
to this
return hashCode() == object.hashCode();
obviously reduces CC by one, even by your quick table. There is only one path through the second version.
For the other case, while we can't know exactly how your plugin calculates those figures, it is reasonable to guess that it is treating if (object == null || getClass() != object.getClass()) as "if a non-null object's class matches then ...", which is a single check and thus adds just one to CC. I would consider that a reasonable shortcut since null checks can be rolled up into "real" checks very easily, even within the human brain.
My opinion is that the main aim of a CC-calculating IDE plugin should be to encourage you to make your code more maintainable by others. While there is a bug in the plugin (that inlined single-line conditional is not particularly maintainable), the general idea of rewarding a developer by giving them a better score for more readable code is laudable, even if it is slightly incorrect.
As to your final question: CC is 5 if you strictly consider logical paths; 4 if you consider cases you should consider writing unit tests for; and 3 if you consider how easy it is for someone else to quickly read and understand your code.
In the second method
return hashCode() == object.hashCode(); costs 0 so you win 1. It's considered as calculation and not logical branch.
But for the first method I don't know why it's cost 5, I calculate 4.
As far as style is concerned, I consider the following the most readable:
public boolean equals(Object object) {
return this == object || (object != null && eq(this, object));
};
private static boolean eq(Object x, Object y) {
return x.getClass() == y.getClass()
&& x.hashCode() == y.hashCode(); // safe because we have perfect hashing
}
In practice, it may not be right to exclude subclasses from being equal, and generally one can not assume that equal hash codes imply equal objects ... therefore, I'd rather write something like:
public boolean equals(Object object) {
return this == object || (object instanceof MyType && eq(this, (MyType) object));
}
public static boolean eq(MyType x, MyType y) {
return x.id.equals(y.id);
}
This is shorter, clearer in intent, just as extensible and efficient as your code, and has a lower cyclomatic complexity (logical operators are not commonly considered branches for counting cyclomatic complexity).

Format a Date, allowing null

I'm trying to print a Date, just the way DateFormat.getDateTimeInstance() does it.
format throws a NullPointerException when passing null, so I've been wondering if there is a different approach that would return null (or "null") instead?
Something I'd call instead of
Date d = null;
System.out.println(d==null ? null : DateFormat.getDateTimeInstance().format(d));
You could just wrap the call inside a utility method :
public class DateUtils {
public static String formatDateTime(Date dateOrNull) {
return (dateOrNull == null ? null : DateFormat.getDateTimeInstance().format(dateOrNull));
}
}
private constructor and javadoc omitted for brevity.
What's the problem with your existing code?
null is kind of a special case, and you've decided that you want one particular behaviour in this case (returning "null") instead of another particular behaviour (throwing an NPE). It's arguably cleaner to express this via switching at the top level rather than burying this logic within the formatting method.
It might be a little cleaner to use a full if-else rather than a tertiary operator, though, to make it clearer that there are two distinct branches (normal, and special-cased null):
if (d == null) {
return "null"; // or whatever special case
}
else {
return DateFormat.getDateTimeInstance().format(d);
}
The return value in the null case should be made clear in your method's javadocs, too.

Using Return Stylishly

Let's say I had a lot of code between an if statement. Is it more proper to do a quick if-else check before it, and if it fails, return.
OR create the if statement with a lot of code in-between but not use return?
OR is it just a matter of preference?
so my 2 options are:
if(!something){
return
}
else
//lots of code here
if(something){
//lots of code here
}
From a performance perspective, you should always return from a function as quickly as you can, avoid doing unnecessary computations, "short-circuit" if you will. So checking for error cases and returning quickly would be the better policy.
Edit to add: In the same vein, you should always check the cases that are most likely to be violated first, this is sound advice when structuring your conditionals as well (|| and && checks)
I think this looks much nicer:
func() {
if(someCondition) {
return;
}
if(otherCondition) {
return;
}
//lots of code
}
than this:
func() {
if(someCondition) {
return;
} else if(otherCondition) {
return;
} else {
//lots of code
}
}
or this:
func() {
if(!someCondition) {
if(!otherCondition) {
//lots of code
}
}
}
It looks even uglier with more conditions, so I generally use the first method.
I prefer "shortcut". It has nothing to do with performance, as modern computer can handle if-else very fast, so we should focus on code readability.
However, if there's so many if-else in code, you may re-think your design. Refactory can be a better choice.
Readability and performance are not necessary conflicting constraints but when they are I tend to give readability the front seat.
To enhance readability I tend to follow the following rules.
Rule 1. Keep return as the last line of code, whatever comes in the middle. In other words don't sprinkle return statements whenever you want just because you're not too sure your if-else structure will cascade down just before the final return.
Except may be for the simplest methods I privilege a structure like
MyType func() {
MyType result ;
if ( condition ) {
result = result_1 ;
} else {
result = result_2 ;
}
return result ;
}
over an allegedly simpler
MyType func() {
if ( condition ) {
return result_1 ;
} else {
return result_2 ;
}
}
In my opinion the performance cost, if any, is negligible. However, when scaled up, I find the first coding pattern much more readable.
Rule 2. Refrain from starting a logic by "evacuating" error conditions, just in order to get them out of the way and free your mind. If your logic is well thought these checks will find their place in the logic (also have a look at guava for many well though techniques of encapsulating routine checks in helpers).
Many freshmen in my team start coding things like this
MyType func (ArgType arg1,...) {
if ( arg1 == null ) {
throw new Exception ( "hey dummy, we don't take null arg1) ;
// or return null ;
}
if ( arg2 == null ) {
// you got the picture...
}
// wow at last !!! all checks done
// Combine args and return result...
}
Which I have to say, is already a progress on just taking all conditions for granted
I tend to prefer
MyType func (ArgType arg1,...) {
MyType result ;
if ( try_to_compact_all_checks_here ) {
// Combine args and return result...
} else {
// throw, log, nullify result etc
}
return result ;
}
If the condition "try_to_compact_all_checks_here" does not fit in one line, I even sometimes prefer to get out of my way and I encapsulate all the checks in a private function. Even if it's called only once.
Rule 3. Keep the number of lines in an if/else statement to a reasonable amount (basically should fit on one screen in your IDE). To do so it is sometimes possible to extract some logic and stick it into a private function. No problem at all. All modern IDE do that for you in 2 clicks.
So basically the previous template becomes.
MyType func (ArgType arg1,...) {
MyType result ;
if ( checks_here ) {
// 1 to 20 lines max,
encapsulate lengthy logic in full fledged private methods.
} else {
// throw, log, nullify result etc
}
return result ;
}
Rule 4. Inner IFs should always have an ELSE, and that ELSE should be different from the outer ELSE.
Explanation: If I end up with
MyType func (ArgType arg1,...) {
MyType result ;
if ( check_1 ) {
if (check_2) {
Do the real work
} else {
treat error condition
}
} else {
same error condition as above
}
return result ;
}
Then it's probably because my check analysis is not complete. It happens quite often.
I try to reach
MyType func (ArgType arg1,...) {
MyType result ;
if ( check_1 && check_2) {
Do the real work
} else {
same error condition as above
}
return result ;
}
That's all.
I found that, by observing this kind of conventions, I can process large Java projects with ofter complex business logics (like in ESBs, Web Services etc), at very little performance cost if any.

Categories