Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Java 8: Oogway's Advice on Optional

DZone's Guide to

Java 8: Oogway's Advice on Optional

How do Optionals protect us from NPEs? Let's examine their usefulness in the context of an API developer and a caller.

· Java Zone ·
Free Resource

How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

While Po was reading about Java 8 Optionals, a few questions popped into mind. Why was it added to Java? How does it save us from the almighty villain the null pointer exception?

So, he goes to Master Shifu, but the irony is that Shify was also unsure of how Optional will save the Java villagers from NPEs. But Oogway foretold their arrival, so they went to Oogway for advice on Optionals.

I was there when the conversation happened, and I will try to depict it here.

Po: Master Oogway, I am really confused. Why was Optional added in Java? I can't see any benefits, and I am a little bit surprised with how it saves us from null pointer exceptions. It is nothing but a container/wrapper object holding a reference to another object. I understand that the reference can be null, but I am confused about the use case.

Oogway: Since the birth of Java the greatest sin has been the invention of null. Java tries to represent something absent as a null, but absent does not mean null — it means not present (and there are multiple reasons to be not present). Java is a strongly typed language, but null is a value that can be assigned to any type, so it acts as a loose type variable. It is not a blessing, it is a curse.

Every time a developer doesn't know what the returned object would be, they return a null. And the caller, unfortunately, bears the load of the null check for the return value unless the null pointer exception blows up the flow. It is a breach of encapsulation

Let's see a small example:

package com.example.optional;

import java.util.ArrayList;
import java.util.List;

public class OptionalTest {
    private static List <String> nameList = new ArrayList <String> ();
    static {
        nameList.add("Shamik");
        nameList.add("Samir");
        nameList.add("Swastika");
    }

    public String findName(String nameToFind) {
        return nameList.contains(nameToFind) ? nameList.get(nameList.indexOf(nameToFind)) : null;
    }

    public static void main(String[] args) {
        OptionalTest test = new OptionalTest();
        String searchedName = test.findName("Mayukh");
        System.out.println(" Hi , " + searchedName.toUpperCase());
    }

}


Here, the API developer exposes a method called findName and silently returns a null if the name is not found.  The caller of the API trusts the API developer and calls the method with an arbitrary name, trying to print it in uppercase. But it blows up the caller's code with a null pointer exception.

Whose fault is it — the caller or the API developer?

API developer's perspective: When the caller gives a name and that name is not found in the nameList, what should I do? Return a blank string or return a string with "NA"? But if the caller says that they don't want "NA" or a blank string, I am not sure what to return, so I always return null. Yes, I am a good developer, and I can handle all the boundary cases.

Caller's perspective: findName is an API method. I only command it to give me a search result — "Tell, Don't Ask". It is the API method's responsibility to handle boundary cases or cases where the searchable name is not found. It should give me a dummy implementation if the searchable name not found, like "NA". So I do not bother to check the return value. It is not my responsibility. So I skip the null check and the program blows up.

API Dev or Caller: Really, Who's Fault Is It?

The caller and developer are right in their perspectives. The confusion occurs because the API developer can't signal the caller that the return value may be present or absent. Null means no reference! But how will the caller understand that the current returned reference does not point to any object instance?

It is always the caller's responsibility to do a null check — even if the value is present. Null is not expressive enough to indicate to the caller that a value is present or absent, as it can be easily and silently assigned to a return value.

So, Optional steps in here and it tries to say that a value may be present or absent, so caller, it is your duty to check whether the value is present or absent, whereas null returns silently without informing you about the nature of the value.

Optional acts as a container. It holds the reference and provides a method to test whether the reference inside is present or absent.

Let's see how we can return Optional with the above example:

package com.example.optional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class OptionalTest {
    private static List <String> nameList = new ArrayList <String> ();
    static {
        nameList.add("Shamik");
        nameList.add("Samir");
        nameList.add("Swastika");
    }

    /*public String findName(String nameToFind){
    return nameList.contains(nameToFind)?nameList.get(nameList.indexOf(nameToFind)):null;
    }*/
    public Optional <String> findName(String nameToFind) {
        return nameList.contains(nameToFind) ? Optional.of(nameList.get(nameList.indexOf(nameToFind))) : Optional.empty();
    }

    public static void main(String[] args) {
        OptionalTest test = new OptionalTest();
        Optional <String> searchedName = test.findName("Mayukh");
        if (searchedName.isPresent()) {
            System.out.println("HI," + searchedName.get());
        } else {
            System.out.println("Name not found");
        }
    }

}


Here, I use the Optional.of() method, which creates a new Optional object with the value passed in the 'of' method as a parameter. If the value is not found in nameList, I return an empty Optional that does not contain anything. Don't say it contains a null — empty represents that the value is absent. This way, we say to the caller that our method may give you a result that does not contain anything, so prepare for it.

Po: Master Oogway, I understood your point, but I am still confused. Here, the caller has to check if(Optional.ispresent()) to see whether a value which is present, but if the caller forgets to do that check, it gives you a NoSuchElement exception. So, what is the value of using Optional? It seems that it just changed the null pointer exception to a NoSuchElement exception. What is the point?

Oogway: Haha, that's why I chose you as a Dragon Warrior. You are intelligent and to the point. You learn new things very quickly. Let me share some thoughts.

Null is omnipresent — no one can ever remove or defeat it completely. What we can do is protect ourselves from nulls' rage by educating our Java villagers.

Optional is like a warning bell in the city. Rather than nulls coming silently, with the Optional API, developers can warn Java villagers/callers that they might enter your village at any point in time.

So my point is, until now, only efficient villagers or callers understood how to escape from NPEs' rage. But still, in a complex call or with lots of chained calls, they fall into the null pointer trap. Optional tries to fix that. It reminds us about absent values, which can come at any time.

Optional does not remove the null pointer exception — it warns callers to handle the absent scenarios.

It is not a technical improvement, but rather, it is a conceptual improvement added to Java 8 that educates Java programmers to handle a scenario where a value can be present or absent.

PO: I realize this Master. Now, tell me the best practices of Optional.

Oogway: It is too late for that today. Please, come back tomorrow and I will discuss them.

Conclusion

Oogway taught us a valuable lesson — Optional is not a replacement for the null check. Rather, it tries to tell the caller about the nature of the returned value and implicitly reminds the caller to handle the absent cases.

If the caller forgets to do that, it will end up with the NoSuchElement exception, which is clear evidence that you are trying to do an operation where the element/value is not present. It is a big conceptual improvement. It encourages the caller to handle absent cases, unlike the null return value, where the caller is unsure whether the API developer has already tackled the null value.

How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

Topics:
java ,optional ,java 8 ,null pointer exception ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}