How to escape NullPointerExceptions in Java using Optional
Tags: java, webdev, programming, tutorial
Published: 2021-03-24 08:17:31

# What is Optional? 🤔
According to **Oracle**: "A container object which may or may not contain a non-null value."

# Why use it? 👀
it was introduced in **Java 8** to enable us to elegantly handle the Null pointer exception problem.


# How?

Let's first start by learning how variables in Java are handled in memory and what **NullPointerException** means.

In java variables can be one of two types:

 - **Primitives**
	 - They are [8 types](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) (int, char, etc...) 
	 - They are saved in the execution stack of the current method.
	 - Fast info: each method call has its own execution stack.
            
```java
 public void someMethod(){  
        int x = 10;  
}
```

 -  **Objects**

	 - They are instances of classes (User, Car, Integer)
	 - They are saved in the Java Heap, however, references to them are saved in the execution stack of the current method as well.
	 - Those references are saved into variables.
```java
    public void someMethod(){  
        // the local variable car is a reference to the actual object value in the Heap  
      Car car = new Car();  
    }
```
# Where does null fit in the picture? 🖼️
If an object isn't referencing any value in the Heap, then its value is null.
When we try to do some operations using that variable we hit the famous **NullPointerException**.
```java
    Car car;  
    car.getModel();
```
# How does the Optional help?

It wraps the objects we pass to the calling method, and it provides methods to handle the presence or absence of the null value in a clean code functional style.

# Code time 🤖
As an example, let's say we have a Room class, which has a Desk, and that Desk has Pen Holder

First, let's look at some code that **doesn't** use the **Optional** class

Room 🏠
```java
@Getter @RequiredArgsConstructor @AllArgsConstructor
public class Room {
    private Desk desk;
    private final int number;
}
```

Desk 🗃
```java
@Getter @RequiredArgsConstructor @AllArgsConstructor
public class Desk {
    private PenHolder penHolder;
    private final String model;
}
```

Pen Holder 🖊
```java
@Getter @RequiredArgsConstructor
public class PenHolder {
    private final int capacity;
}
```
A service that tells us what is the capacity of the Pen holder in a room, if exists. It has two methods, one that does a null check and another that doesn't
```java
public class FetchingService {
    // this method will throw a nullPointerException when
    // either the Desk or PenHolder are null
    public static int getCapacityOfPenHolder_NoNullCheck(Room room){
        return room.
                getDesk().
                getPenHolder().
                getCapacity();
    }
    // this method performs a null check on both Desk and PenHolder
    public static int getCapacityOfPenHolder(Room room){
        if (room.getDesk() == null){
            return 0;
        }
        else if (room.getDesk().getPenHolder() == null){
            return 0;
        }
        else return room.getDesk().getPenHolder().getCapacity();
    }
}
``` 

Now let's apply **Optional** and see the results

Room 🏠
```java
@AllArgsConstructor @RequiredArgsConstructor @Getter
public class Room {
    private Desk desk;
    private final int number;

    public Optional<Desk> getDeskOpt(){
        return Optional.ofNullable(desk);
    }
}
```
Desk 🗃
```java
@Getter @AllArgsConstructor @RequiredArgsConstructor
public class Desk {
    private PenHolder penHolder;
    private final String model;

    public Optional<PenHolder> getPenHolderOpt(){
        return Optional.ofNullable(penHolder);
    }
}
```
Pen Holder 🖊
```java
@RequiredArgsConstructor @Getter
public class PenHolder {
    private final int capacity;
}
```
The service
```java
public class FetchingService {
    public static int getCapacityOfPenHolder(Room room){
        return room.
            getDeskOpt().
            flatMap(Desk::getPenHolderOpt).
            map(PenHolder::getCapacity).
            orElse(0);
    }
}
```
The optional code is much more concise, clear, and clean. However, the most important side is that we got rid of the **NullPointerException** monster.

## One thing to be careful of is to not return null instead of the Optional<T>. 🔥

```java
public Optional<PenHolder> getPenHolderOpt(){
        if (penHolder == null)
            return null;
        else return Optional.ofNullable(penHolder);
    }
```
# Where to use Optional?
There are a number of options for the place that we might use the Optional wrapper class, for example,  wrap method parameters, local variables. However, the most suitable place is on **method return types**.

```java
public class Desk {
    // not good !!!!
    private Optional<PenHolder> penHolder;
    private final String model;
}
```
```java
public class Desk {
    private PenHolder penHolder;
    private final String model;
    // Yes !!!
    public Optional<PenHolder> getPenHolderOpt(){
        return Optional.ofNullable(penHolder);
    }
}
```

# Conclusion

 - The Optional class is a wrapper that wraps objects that might not exist in the Heap (in other words that could be null).
 
 - It was created to reduce the possibility of facing a NullPointerException
 
 - This class has methods that help us write clean code.

# Code 👩‍💻
[GitHub](https://github.com/Jarjanazy/java-optionals)