1. The dangous of null

et’s consider a nested object structure for a Computer, as illustrated in Figure 1.
Null and Optional - 图1
What’s possibly problematic with the following code?
String version = computer.getSoundcard().getUSB().getVersion();
This code looks pretty reasonable. However, many computers (for example, the Raspberry Pi) don’t actually ship with a sound card. So what is the result of getSoundcard()?
A common (bad) practice is to return the null reference to indicate the absence of a sound card. Unfortunately, this means the call to getUSB() will try to return the USB port of a null reference, which will result in a NullPointerException at runtime and stop your program from running further. Imagine if your program was running on a customer’s machine; what would your customer say if the program suddenly failed?
To give some historical context, Tony Hoare—one of the giants of computer science—wrote, “I call it my billion-dollar mistake. It was the invention of the null reference in 1965. I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement.”
What can you do to prevent unintended null pointer exceptions? You can be defensive and add checks to prevent null dereferences, as shown in Listing 1:

  1. String version = "UNKNOWN";
  2. if(computer != null){
  3. Soundcard soundcard = computer.getSoundcard();
  4. if(soundcard != null){
  5. USB usb = soundcard.getUSB();
  6. if(usb != null){
  7. version = usb.getVersion();
  8. }
  9. }
  10. }

2. Optional in a Nutshell

Java SE 8 introduces a new class called java.util.Optional<T> that is inspired from the ideas of Haskell and Scala. It is a class that encapsulates an optional value.
Null and Optional - 图2

A. Creating Optional objects

  • Empty Optional: Optional<Soundcard> sc = Optional.empty();
  • Optional with a non-null value:

    1. SoundCard soundcard = new Soundcard();
    2. Optional<Soundcard> sc = Optional.of(soundcard);

    If soundcard were null, a NullPointerException would be immediately thrown (rather than getting a latent error once you try to access properties of the soundcard).

  • Create an Optional object that may hold a null value:

Optional<Soundcard> sc = Optional.ofNullable(soundcard);
If soundcard were null, the resulting Optional object would be empty.

B. Do sth if Optional is not empty

You can also use the isPresent() method to find out whether a value is present in an Optional object. get() can only return a value if the wrapped object is not null; otherwise, it throws NoSuchElementException.

  1. if(soundcard.isPresent()){
  2. System.out.println(soundcard.get());
  3. }

However, this is not the recommended use of Optional (it’s not much of an improvement over nested null checks), and there are more idiomatic alternatives, which we explore below:

  • You can use the ifPresent() method, as follows:

    1. Optional<Soundcard> soundcard = ...;
    2. soundcard.ifPresent(() -> System.out.println("ok"));
  • Using an Optional object, you can rewrite this code by using the orElseGet() method, which provides a default value if Optional is empty:

    1. Soundcard soundcard = maybeSoundcard.orElseGet(new Soundcard("defaut"));
  • Similarly, you can use the orElseThrow() method, which instead of providing a default value if Optional is empty, throws an exception:

    1. Soundcard soundcard = maybeSoundCard.orElseThrow(IllegalStateException::new);

    3. Rejecting Certain Values Using the filter Method

    ```java USB usb = …; if(usb != null && “3.0”.equals(usb.getVersion())){ System.out.println(“ok”); }

//This pattern can be rewritten using the filter method on an Optional object, as follows: Optional maybeUSB = …; maybeUSB.filter(usb -> “3.0”.equals(usb.getVersion()) .ifPresent(() -> System.out.println(“ok”));

  1. <a name="IHGoI"></a>
  2. ## 4. When to Not Return `Optional`
  3. Generally speaking, for getters in POJOs, it's more suitable to return the actual type, not an _Optional_ type. Particularly, it's important for Entity Beans, Data Models, and DTOs to have traditional getters.<br />We'll examine some of the important use cases below.
  4. <a name="tFtMW"></a>
  5. ### A. Serialization
  6. ```java
  7. public class Sock implements Serializable {
  8. Integer size;
  9. Optional<Sock> pair;
  10. // ... getters and setters
  11. }

This actually won’t work at all. If we were to try and serialize this, we’d get an NotSerializableException:

  1. new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(new Sock());

And really, while serializing Optional may work with other libraries, it certainly adds what may be unnecessary complexity.

B. JSON

Let’s say we have a bean with an optional property:

  1. private String firstName;
  2. public Optional<String> getFirstName() {
  3. return Optional.ofNullable(firstName);
  4. }
  5. public void setFirstName(String firstName) {
  6. this.firstName = firstName;
  7. }

So, if we use Jackson to serialize an instance of Optional, we’ll get:

  1. {"firstName":{"present":true}}

But, what we’d really want is:

  1. {"firstName":"Baeldung"}

C. JPA

In JPA, the getter, setter, and field should have name as well as type agreement. For example, a firstName _field of type _String _should be paired with a getter called _getFirstName that also returns a String.
Until JPA has elegant support of Optional type, we should stick to the traditional code. It’s simpler and better: