A New Way to Check for Null — Say Goodbye to if-else — -part 1

At the beginning of the article, let’s address the issue of NPE, which stands for NullPointerException, a problem commonly encountered in development. Suppose we have two classes, and their UML class diagram is as shown below:

In this situation, if we have a piece of code like the following, you will get NPE.
user.getAddress().getProvince();
We can use if-else to resolve this.
if(user!=null){
Address address = user.getAddress();
if(address!=null){
String province = address.getProvince();
}
}However as a senior developer, you SHOULD avoid this kind of ugly code. We can take advantage of Java8's Optional class to optimise this block.
1、 Optional(T value),empty(),of(T value),ofNullable(T value)
First, let’s clarify that the ‘Optional(T value)’ constructor has private access and cannot be called externally.
The source code of `Optional(T value)` looks like this:
private Optional() {
this.value = null;
}The other three functions are public and meant to be used by us.
The source code of `of(T value)` looks like this:
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}We can reach two conclusions:
- An ‘Optional’ object constructed via the ‘of(T value)’ function will still result in a NullPointerException if the ‘value’ is null.
- When the ‘value’ is not null, you can successfully create an ‘Optional’ object.
in addition to that, in the Optional class, we have a null object
public final class Optional<T> {
//....
private static final Optional<?> EMPTY = new Optional<>();
private Optional() {
this.value = null;
}
//...
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
}So the method empty() is used to return then EMPTY object.
What does ofNullable(T value) looks like?
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}The key difference between ‘of(T value)’ and ‘ofNullable(T value)’ is that when the ‘value’ is null, ‘of(T value)’ will throw a NullPointerException, while ‘ofNullable(T value)’ won’t throw an exception but instead returns an EMPTY object.
Does this mean we should always use ‘ofNullable’ exclusively in our projects and avoid ‘of’? Not necessarily. Everything has its purpose. If during runtime, you don’t want to hide the NullPointerException but want it to be reported immediately, in such cases, you should use ‘of’.
2、orElse(T other),orElseGet(Supplier other) and orElseThrow(Supplier exceptionSupplier)
The three functions can be grouped together for easy recall, as they are all called when the ‘value’ passed into the constructor is null. The usage of ‘orElse’ and ‘orElseGet’ is as follows, which is akin to providing a default value when the ‘value’ is null:
@Test
public void test() {
User user = null;
user = Optional.ofNullable(user).orElse(createUser());
user = Optional.ofNullable(user).orElseGet(() -> createUser());
}
public User createUser(){
User user = new User();
user.setName("John");
return user;
}The difference between these two functions is that when the ‘user’ value is not null, ‘orElse’ will still execute the ‘createUser()’ method, whereas ‘orElseGet’ will not execute the ‘createUser()’ method. (While writing this blog, I found this is an interesting topic, I will discuss this in my NEXT blog.)
As for ‘orElseThrow,’ it means that when the ‘value’ is null, it will directly throw an exception.
User user = null;
Optional.ofNullable(user).orElseThrow(()->new Exception("No such user"));3、map(Function mapper) and flatMap(Function> mapper)
if the structure of User looks like this:
public class User {
private String name;
public String getName() {
return name;
}
}if you want to get the name, then you should use the following code piece:
String city = Optional.ofNullable(user).map(u-> u.getName()).get();For flatMap if the structure of User looks like this
public class User {
private String name;
public Optional<String> getName() {
return Optional.ofNullable(name);
}
}if you want to get the name, then you should use the following code piece:
String city = Optional.ofNullable(user).flatMap(u-> u.getName()).get();Let me show some samples to “Kill” if-else by using Optional
Sample1:
public String getCity(User user) throws Exception{
if(user!=null){
if(user.getAddress()!=null){
Address address = user.getAddress();
if(address.getCity()!=null){
return address.getCity();
}
}
}
throw new Excpetion("some exception raised here");
}Java8+ approach
public String getCity(User user) throws Exception{
return Optional.ofNullable(user)
.map(u-> u.getAddress())
.map(a->a.getCity())
.orElseThrow(()->new Exception("some exception raised here"));
}Sample2:
public User getUser(User user) throws Exception{
if(user!=null){
String name = user.getName();
if("John".equals(name)){
return user;
}
}else{
user = new User();
user.setName("John");
return user;
}
}Java8+ approach
public User getUser(User user) {
return Optional.ofNullable(user)
.filter(u->"John".equals(u.getName()))
.orElseGet(()-> {
User user1 = new User();
user1.setName("John");
return user1;
});
}




