Java 8 Optional: What's the Point?

Note: I wrote this article shortly after the release of Java 8. Several years passed and I became an Oracle employee via acquisition. So I need to say in no uncertain terms that this article represents my own opinion and does not in any way represent an official position from Oracle. 100% personal opinion, 0% Oracle opinion. I hope that's clear.

There's a new feature in Java 8 called the Optional class which is supposed to cure NullPointerExceptions. Apparently these annoy developers more than I thought. It seems obvious that an object is really just a pointer and a pointer can point at nothing. Maybe it isn't any more? Perhaps the majority of computer science graduates this century never really learned about pointers since schools have gravitated toward high-level programming languages. I'm not being critical on that point, it's like asking 90s computer science students why they don't know COBOL.

The catch with this new Optional class is of course the word "class". Optional is only a wrapper that contains a reference to some other object and isn't close to being a panacea for NullPointerExceptions.

Let's start by creating a very simple example that generates a NullPointerException:


import java.util.Optional;
public class OptionalTest{
public String getNullString(){
  return(null);
}
public Optional<String> getOptionalNullString(){
  return(null);
}
public static void main(String[] args){
  OptionalTest optionalTest=new OptionalTest();
  String nullString=optionalTest.getNullString();
  try{
    System.out.println(nullString.toString());
  }catch(NullPointerException x){
    System.out.println("Oh the humanity, a NullPointerException!");
}

Yes, the toString() is redundant but it guarantees a NullPointerException which is what we're trying to demo. So here's the dreaded old-school solution to this problem:


if(nullString!=null){
  System.out.println(nullString.toString());
}else{
  System.out.println("nullString is null, man that check was a lot of work");
}

So here comes Optional to the rescue; except Optional is an object so it can be null too:


Optional<String> optionalString=optionalTest.getOptionalNullString();
try{
  if(optionalString.isPresent()){
    System.out.println(optionalString.get().toString());
  }
}catch(NullPointerException x){
  System.out.println("Optional object can be null, sorry dude.");
}

OK, so that's maybe not the intended usage of the class. You're supposed to use a static method like Optional.of to create an instance. This will throw a, you guessed it, NullPointerException if a null value is passed. So if the goal is to avoid NullPointerExceptions then this particular method is only useful if you already know you're assigning a non-null value in which case why do you even need Optional? Example:


try{
  optionalString=Optional.of(optionalTest.getNullString());
  if(optionalString.isPresent()){
    System.out.println(optionalString.get().toString());
  }
}catch(NullPointerException x){
  System.out.println("NullPointerException, I thought Optional totally banished these?!");
}

So instead we have Optional.ofNullable to create an instance of Optional that might contain a null value. Instead of the terrible burden of checking for a null reference we can call the ifPresent method on Optional:


optionalString=Optional.ofNullable(optionalTest.getNullString());
optionalString.ifPresent(s->{System.out.println(s.toString());});

I'm really stuck on why that is preferable to this:


String s=optionalTest.getNullString();
if(s!=null){System.out.println(s.toString());}

I guess with Optional you can feel l337 by using lambda expressions inside ifPresent.

There are two other drawbacks to this new Optional class:

1) It's a great way to make heap management and debugging stack traces even worse. Again, Optional is a wrapper which means if you use it you'll now have two object references where you used to have one.

2) It's not serializable making it useless for many cases.

So to recap - in an attempt to get rid of NullPointerExceptions we have a new class that:

-Throws NullPointerExceptions

-Can itself be null, causing a NullPointerException

-Increases heap size

-Makes debugging more difficult

-Makes serializing objects, say as an XML or JSON for an external client, much more difficult

All I'm left with here is "what's the point?"

Maybe I'm just being a grumpy old programmer here so if someone could point me to the benefits of this new feature I'm open to reconsidering my view.



Related