• Post Reply Bookmark Topic Watch Topic
  • New Topic

Alternatives to null checks in if, else if, else statements?  RSS feed

 
Tim Cooke
Marshal
Posts: 4051
239
Clojure IntelliJ IDE Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have some code that looks like this:

I don't like this code very much for two reasons: 1) The explicit null checks, and 2) The hard to read conditions.

I figured there might be something in the Java 8 tool kit that would help me out. My first idea was to use Optional with the intention of being able to handle the 'null' condition more gracefully and in the hope it would result in a more pleasant usage pattern. However, in my attempt I appear to have just replaced the null check with .isPresent() instead:

Not much better.

Does anyone have any better ideas I can try?
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Not really except:

 
Paweł Baczyński
Bartender
Posts: 2087
44
Firefox Browser IntelliJ IDE Java Linux Spring
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What about this?
 
Stephan van Hulst
Saloon Keeper
Posts: 7993
143
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16060
88
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You could ofcourse use ? :

Or, if you find the nested ? : too unreadable
 
Tim Cooke
Marshal
Posts: 4051
239
Clojure IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the suggestions all.

Paweł has the closest to the kind of thing I was aiming for, in that he's gotten rid of the null entirely. However, the readability isn't perfect. I might be able to work with it though.

A.J. Côté: The nested conditional make it even less readable to me.
Stephan: Shame on you for omitting braces from your conditional blocks. Although the ordering is better with just a single condition per if.
Jesper: Nested ternary conditions ... ick!
 
Stephan van Hulst
Saloon Keeper
Posts: 7993
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Egh, I've already accepted that I'll get flak for my lack of use of braces. I use them everywhere at the office, but for my own projects I prefer to omit them. And yeah, I've heard all the reasons against them :P

Honestly, I'm not so sure why null is evil, if the alternative is something like this:



Another alternative:


I stand by my original post though :p
 
Paweł Baczyński
Bartender
Posts: 2087
44
Firefox Browser IntelliJ IDE Java Linux Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I prefer using orElseGet() rather than orElse() because it does not create unnecessary objects.
 
Stephan van Hulst
Saloon Keeper
Posts: 7993
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're correct. I amended my post.
 
Stephan van Hulst
Saloon Keeper
Posts: 7993
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Wait, only now do I see it's exactly the same as yours XD

Yes, using a helper method is better. I've noticed that since Java 8 came out, I'm going overboard with functional code, and have made an effort to go back to plain old if, else, for, etc. constructs, which in a lot of situations really do read a lot easier.
 
Tim Cooke
Marshal
Posts: 4051
239
Clojure IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the help guys. In the end I went with Paweł / Stephan's suggestion:

I think it reads ok, but there'll no doubt be some chats about it during the code review.
 
Tim Cooke
Marshal
Posts: 4051
239
Clojure IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Now, in my attempt to simplify I may have omitted important details. createAnonymousUser() actually takes arguments and my compiler complained terribly when I tried to use orElseGet with it.

Perhaps I just don't understand the difference between orElse and orElseGet?
 
Paweł Baczyński
Bartender
Posts: 2087
44
Firefox Browser IntelliJ IDE Java Linux Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
orElse takes T as an argument.
So a call to createAnonymousUser() is always made, even when the result is unnecessary.

orElseGet takes Supplier<? extends T> as an argument.
A Supplier in form () -> createAnonymousUser() would call createAnonymousUser() only when necessary.
 
Tim Cooke
Marshal
Posts: 4051
239
Clojure IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Which would be particularly bad if createAnonymousUser() had side effects. That's really good to know. Thanks. See, I'll get the hang of this Java 8 malarkey eventually
 
Campbell Ritchie
Marshal
Posts: 56600
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Anything which contains a -> is tending towards functional programming. And functional programmers really hate side effects.
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I enjoyed reading this thread, very entertaining ;-)

Cheers to all!
 
Phil Freihofner
Ranch Hand
Posts: 128
4
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It might be better coding to have your getUserID() return a "blank user" rather than a null. Returning nulls in general is a suspect practice. How is the following for clarity?


Since UserInfo is an object, why not have a property that shows the type, and can be used in a Switch structure? Also, why not let the various create..() methods extract the ID or whatever it is that the method needs? Doing so as an inline parameter just clutters things up and doesn't really save any processing time.

The above ideas can also be used in a normal sort of if..else if..else structure. Main thing, just don't return nulls.
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I would recommend against creating dummy objects. For me returning nulls is fine.

If you do this all over your code, your application will be much slower.

http://www.coderanch.com/t/656741/java/java/Creating-objects-abstract-classes#3043731

In the example below the code runs 10 times slower:

output:
200000000
10




If you have performance in mind you could always create a dummy object once and always return the same dummy object although you will end up using more memory if you do it all over your code but I guess this is more negligible.

Below, performance is the same:

output:
200000000
1







 
Stephan van Hulst
Saloon Keeper
Posts: 7993
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That benchmark is not reliable because it doesn't take VM warmup into account. I wouldn't be very surprised if the second loop ran a lot faster if you ran it before the first loop.

Since Java 8, Instead of returning null, I've gotten into the habit of returning Optional.
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:That benchmark is not reliable because it doesn't take VM warmup into account. I wouldn't be very surprised if the second loop ran a lot faster if you ran it before the first loop.

Since Java 8, Instead of returning null, I've gotten into the habit of returning Optional.


This should be warm enough and loops are inversed ;-)

output:
200000000
8



>
 
Phil Freihofner
Ranch Hand
Posts: 128
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi A.J. -

I agree that there are good and bad ways to implement the passing of a "None" object. However, I don't think your example is entirely sound.


Results I get:
200000000
6

I made a small alteration, and the passing and testing of null now takes 6 times longer than NONE. This probably has more to do with testing order than anything else. But mostly, it just goes to show how difficult it is to make sound microtests. I notice that there are also troubles with the test you presented on your link.

 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:Since Java 8, Instead of returning null, I've gotten into the habit of returning Optional.


Great, but you are still creating objects for nothing. It is even slower than what the other poster suggested to avoid nulls, 24 times slower than simply returning nulls.

output:
200000000
24



>
 
Stephan van Hulst
Saloon Keeper
Posts: 7993
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A.J. Côté wrote:Great, but you are still creating objects for nothing. It is even slower than what the other poster suggested to avoid nulls, 24 times slower than simply returning nulls.


Not for nothing. Intent is more clear, chained usage is easier (through the map() operation) and it's simply more semantic.

The speed rarely ever matters. I've never had to profile my application because it was to slow, and found the problem was that I created objects where I could have used null instead. I don't care if runs ten times or even hundred times slower than it could, if it's still a tiny fraction of the rest of the execution time of the program.
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:
Since Java 8, Instead of returning null, I've gotten into the habit of returning Optional.


Just use the recommendation in my first post if you insist on using Optional

output:
200000000
1.5333333333333334

>
 
Campbell Ritchie
Marshal
Posts: 56600
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A.J. Côté wrote:. . . For me returning nulls is fine.
. . .
But it won't be for anybody who uses your code and suffers null pointer exceptions.
 
Paweł Baczyński
Bartender
Posts: 2087
44
Firefox Browser IntelliJ IDE Java Linux Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
By the way, instead of Optional.ofNullable(null) you could just write Optional.empty().
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:
The speed rarely ever matters.


It doesn't matter when you are the only single user of your application. In real life, with thousands of users, it matters a lot, trust me.
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paweł Baczyński wrote:By the way, instead of Optional.ofNullable(null) you could just write Optional.empty().


Interesting, it seems to always return the same Object although the javadoc says there is no guarantees that it is a singleton.


public static <T> Optional<T> empty()

Returns an empty Optional instance. No value is present for this Optional.

API Note:
Though it may be tempting to do so, avoid testing if an object is empty by comparing with == against instances returned by Option.empty(). There is no guarantee that it is a singleton. Instead, use isPresent().
Type Parameters:
T - Type of the non-existent value
Returns:
an empty Optional



output:
200000000
1.4095238095238096






 
Campbell Ritchie
Marshal
Posts: 56600
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A.J. Côté wrote:. . . it seems to always return the same Object . . .
It might not in future versions. It is convenient to have a singleton to represent empty(). But what happens if you try this sort of thing?I expect it will show false but I shan't cry if it turns out to print true.
 
Campbell Ritchie
Marshal
Posts: 56600
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The API documentation for Optional#empty wrote:API Note:
Though it may be tempting to do so, avoid testing if an object is empty by comparing with == against instances returned by Option.empty(). There is no guarantee that it is a singleton. Instead, use isPresent().

Link.
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The API documentation for Optional#empty wrote:API Note:
instances returned by Option.empty().
Link.


I can't find the class Option mentioned in the javadocs so I assume it is a typo. Am I correct?

Note: there is a javax/swing/text/html/Option.java but I think it is irrelevant.

 
Paweł Baczyński
Bartender
Posts: 2087
44
Firefox Browser IntelliJ IDE Java Linux Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A.J. Côté wrote:I can't find the class Option mentioned in the javadocs so I assume it is a typo. Am I correct?

You are correct. It should say instances returned by Optional.empty().
Well spotted!
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paweł Baczyński wrote:
A.J. Côté wrote:I can't find the class Option mentioned in the javadocs so I assume it is a typo. Am I correct?

You are correct. It should say instances returned by Optional.empty().
Well spotted!


The guy/girl who wrote the doc is probably using scala...
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:
A.J. Côté wrote:. . . it seems to always return the same Object . . .
It might not in future versions. It is convenient to have a singleton to represent empty(). But what happens if you try this sort of thing?I expect it will show false but I shan't cry if it turns out to print true.



The code above doesn't even compile ;-)
 
Paweł Baczyński
Bartender
Posts: 2087
44
Firefox Browser IntelliJ IDE Java Linux Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A.J. Côté wrote:The code above doesn't even compile ;-)
D:\tmp>javac Main.java
Main.java:7: error: incomparable types: Optional<String> and Optional<Integer>
System.out.println(noString == noNumber); // I expect false
^
1 error


You are right again.
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:
A.J. Côté wrote:. . . For me returning nulls is fine.
. . .
But it won't be for anybody who uses your code and suffers null pointer exceptions.



Optional.get() throws NoSuchElementException

if you return an empty custom object instead, you still have to check if it is empty.

so you have to do:

if (optional.isPresent())
or
if (!myCustomObject.isEmpty())
or
if (myCustomObject != null)

I really don't see any gains here and I find the whole discussion kind of futile. Just return nulls ;-)

If you return your own custom empty object, you may very well fail later, for example while trying to persist it to the database, worse you could end up inserting empty rows in the DB.

I much prefer failing early with a null pointer exception.
 
Paweł Baczyński
Bartender
Posts: 2087
44
Firefox Browser IntelliJ IDE Java Linux Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
An empty Optional won't throw any exception if you call equals on it.
Trying to do the same with null reference will get you a NPE.

Optional has many useful methods like map/flatMap that prevent nested null checks.

Optional has orElse/orElseGet that you can use to provide default values in case the Optional is empty.
 
A.J. Côté
Ranch Hand
Posts: 417
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paweł Baczyński wrote:An empty Optional won't throw any exception if you call equals on it.
Trying to do the same with null reference will get you a NPE.

Optional has many useful methods like map/flatMap that prevent nested null checks.

Optional has orElse/orElseGet that you can use to provide default values in case the Optional is empty.


I am beginning to like the idea:



More seriously, I have never seen nested null checks in my code, I guess it must be a matter of design. The whole thing still seems like a silly religious debate to me.

As well:
Optional was introduced in Java 8 so obviously it is not used throughout the standard Java library - and never will be for the backward compatibility reasons.


So you will never be able to fully integrate your Optional contrarily to scala where it is much more tightly integrated into the language's API.

Thanks,
 
Stephan van Hulst
Saloon Keeper
Posts: 7993
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That makes no sense. Optionals are not for passing arguments. This is much better solved with method overloading, one that takes an Employee and one that takes no arguments.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!