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

Java 8 Optional - Avoid Null and NullPointerException Altogether - and Keep It Pretty

DZone's Guide to

Java 8 Optional - Avoid Null and NullPointerException Altogether - and Keep It Pretty

· Performance Zone ·
Free Resource

SignalFx is the only real-time cloud monitoring platform for infrastructure, microservices, and applications. The platform collects metrics and traces across every component in your cloud environment, replacing traditional point tools with a single integrated solution that works across the stack.

There have been a couple of articles on null, NPE's and how to avoid them. They make some point, but could stress the easy, safe, beautiful aspects of Java 8's Optional. This article shows some way of dealing with optional values, without additional utility code.

The old way

Let's consider this code:

String unsafeTypeDirName = project.getApplicationType().getTypeDirName();
System.out.println(unsafeTypeDirName);

This can obviously break with NullPointerException if any term is null.

A typical way of avoiding this:

// safe, ugly, omission-prone
if (project != null) {
    ApplicationType applicationType = project.getApplicationType();
    if (applicationType != null) {
        String typeDirName = applicationType.getTypeDirName();
        if (typeDirName != null) {
            System.out.println(typeDirName);
        }
    }
}

This won't explode, but is just ugly, and it's easy to avoid some null check.

Java 8

Let's try with Java 8's Optional:

// let's assume you will get this from your model in the future; in the meantime...
Optional<Project> optionalProject = Optional.ofNullable(project);

// safe, java 8, but still ugly and omission-prone
if (optionalProject.isPresent()) {
    ApplicationType applicationType = optionalProject.get().getApplicationType();
    Optional<ApplicationType> optionalApplicationType = Optional.ofNullable(applicationType);
    if (optionalApplicationType.isPresent()) {
        String typeDirName = optionalApplicationType.get().getTypeDirName();
        Optional<String> optionalTypeDirName = Optional.ofNullable(typeDirName);
        if (optionalTypeDirName.isPresent()) {
            System.out.println(optionalTypeDirName);
        }
}

As noted in a lot of posts, this isn't a lot better than null checks. Some argue that it makes your intent clear. I don't see any big difference, most null checks being pretty obvious on those kind of situations.

Ok, let's use the functional interfaces and get more power from Optional:

// safe, prettier
Optional<String> optionalTypeDirName = optionalProject
        .flatMap(project -> project.getApplicationTypeOptional())
        .flatMap(applicationType -> applicationType.getTypeDirNameOptional());
optionalTypeDirName.ifPresent(typeDirName -> System.out.println(typeDirName));

flatMap() will always return an Optional, so no nulls possible here, and you avoid having to wrap/unwrap to Optional.

Please note that I added *Optional() methods in the types for that. There are other ways to do it (map + flatMap to Optional::ofNullable is one). The best one: only return optional value where it makes sense: if you know the value will always be provided, make it non-optional. By the way, this advice works for old style null checks too.

ifPresent() will only run the code if it's there. No default or anything.

Let's just use member references to express the same in a tight way:

// safe, yet prettier
optionalProject
        .flatMap(Project::getApplicationTypeOptional)
        .flatMap(ApplicationType::getTypeDirNameOptional)
        .ifPresent(System.out::println);

Or if you know that  Project has an ApplicationType anyway:

// safe, yet prettier
optionalProject
        .map(Project::getApplicationType)
        .flatMap(ApplicationType::getTypeDirNameOptional)
        .ifPresent(System.out::println);


Conclusion

By using Optional, and never working with null, you could avoid null checks altogether. Since they aren't needed, you also avoid omitting a null check leading to NPEs. Still, make sure that values returned from legacy code (Map, ...), which can be null, are wrapped asap in Optional.

SignalFx is built on a massively scalable streaming architecture that applies advanced predictive analytics for real-time problem detection. With its NoSample™ distributed tracing capabilities, SignalFx reliably monitors all transactions across microservices, accurately identifying all anomalies. And through data-science-powered directed troubleshooting SignalFx guides the operator to find the root cause of issues in seconds.

Topics:
java ,high-perf ,performance ,tips and tricks ,optional ,java 8 ,null ,npe ,nullpointerexception

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}