34

Can someone explain how Optional helps us avoid NullPointerException?

Optional<String> op = someFunc()
if(op.isPresent()) {
   op.get();
}
String possibleNull = op.get();

Isn't this code prone to NullPointerException too? If so, then why is this code preferred over

String op = someFunc()
if(op != null) {
   op.get();
}
String possibleNull = op;

What possible benefit does Optional provide other than the fact that it helps us in knowing whether a function actually had a return value or not

ffff
  • 2,853
  • 1
  • 25
  • 44
  • Possible duplicate of [Uses for Optional](http://stackoverflow.com/questions/23454952/uses-for-optional) – Bryce Rogers Nov 24 '16 at 04:57
  • 1
    Possible duplicate of [Optional vs. null. What is the purpose of Optional in Java 8?](http://stackoverflow.com/questions/28746482/optional-vs-null-what-is-the-purpose-of-optional-in-java-8) – Mritunjay Nov 24 '16 at 05:00
  • Well, for one thing, you can use `x.toString()` on an `Optional` that isn't present, but you can't use it on a `null`. Also something like `x.equals(y)`. – ajb Nov 24 '16 at 05:01
  • I don't think avoiding exceptions is the big benefit [other than what I mentioned in my other comment]. If your code is broken, you won't get `NullPointerException` as often but you might get `NoSuchElementException`. Big deal. I think a bigger benefit is that if you use `Optional` consistently, so that a value can be present or `empty`, then when you get a `NullPointerException` you know that your code did something really wrong, like forgetting to initialize something. – ajb Nov 24 '16 at 05:04

3 Answers3

63

Let's say you want to get a string returned by a function, convert it to upper case, and then print it out. If you have:

String someFunc() { ... }

You might be tempted to write:

System.out.println(someFunc().toUpperCase());

Of course, this throws NullPointerException if someFunc returns null. Instead, suppose we have this:

Optional<String> someFunc() { ... }

Then

System.out.println(someFunc().toUpperCase());

won't work, since Optional doesn't have a toUpperCase method. At this point -- hopefully -- you'll be confronted with an Optional, which should make you think about the case of the Optional being empty. This helps avoid NPEs, but probably only somewhat.

Now you might be focusing on how to get the value out of the Optional, and you might forget about the empty case. Ah, there's a get method:

System.out.println(someFunc().get().toUpperCase());

This brings back the same problem as NPE, except that the exception is NoSuchElementException instead. So if you blindly call get on an Optional, it really is pretty much the same thing as calling a method on a reference without checking whether it's null.

(For this reason, Brian Goetz considers Optional.get to be the biggest mistake in Java 8. See his interview with Angelika Langer JAX 2015 Fragen und Antworten zu Java 8 at about 16 minutes in. I'm not sure it's the biggest, but it is a mistake. People just don't expect get to throw an exception.)

If you're diligent about checking for null references or empty optionals, then

Optional<String> os = someFunc();
if (os.isPresent()) {
    System.out.println(os.get().toUpperCase());
}

is hardly any better than the old

String s = someFunc();
if (s != null) {
    System.out.println(s.toUpperCase());
}

The real advantage of Optional is that it's a library class that has a fairly rich API for dealing with the empty case in a safe way. It's often possible to process the value that might be contained within an Optional by chaining a couple method calls to the method that returned the Optional in the first place. For example, we could rewrite the sample above as follows:

someFunc().map(String::toUpperCase)
          .ifPresent(System.out::println);
Community
  • 1
  • 1
Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
0
String op = someFunc()
if(op != null) {
   op.trim();
}

When the interface someFunc() is invoked above, it doesn't explicitly say that a null value could be returned, so the caller is left to his/her own assumption.

By explicitly returning an Optional, the caller of someFunc() is made aware that the interface could potentially return null. From an interface creator's perspective, it lets him/her be specific about the return value rather than having to document it separately.

Optional<String> op = someFunc()
if(op.isPresent()) {
   op.get().trim();
}
Sashi
  • 1,977
  • 16
  • 15
0

One scenario where Optional is helpful in avoiding NullPointerException is method chaining.

class A {
  private B b;
}
class B {
  private C c;
}
class C {
  private D d;
}

Let's say I have the above classes, and I want to make sure that an instance of class A has a non-null instance of D, but without causing a null pointer exception. If I were to directly call a.getB().getC().getD() != null, then it might throw NullPointerException - say if a.getB() was null.

Of course, I can do

try { 
  a.getB().getC().getD(); 
  // do something
}
catch(NullPointerException e) {
  // handle exception
};

But that doesn't look nice. An elegant solution would be to wrap our objects in optional.

Optional.ofNullable(a).map(A::getB).map(B::getC).map(C::getD).isPresent()

Check this for more.

Aven Desta
  • 2,114
  • 12
  • 27