DevOps Zone is brought to you in partnership with:

From 1998-2001 I was a software engineer for Mercator Software, working mostly with Visual Basic 6. One massive stock crash later I found myself doing a mix of Visual Basic, C#, and Java development at a Fortune 100 company. From 2003-2006 I was lead C#/ASP.NET developer for a content hub there. When the company moved that site to WebSphere Portal I went along for the ride and was a Portal lead developer/team lead from 2007-2010. In 2011 I moved into a Solution Architect role. In 2004 I completed my M.S. in Computer Science from University of Illinois: Chicago. My area of focus was artificial intelligence. Prior to that I earned a B.S. in Computer Science from Elmhurst College. In my spare time I've written a few nerdy Android applications that are freely available on the market. Hugues has posted 3 posts at DZone. View Full User Profile

Java 8 Optional: What's the Point?

05.08.2014
| 15449 views |
  • submit to reddit

 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.

Republished with permission from: http://huguesjohnson.com/programming/java/java8optional.html 

Published at DZone with permission of its author, Hugues Johnson. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Zeljko Trogrlic replied on Thu, 2014/05/08 - 6:00am

Try to learn FP language - advantages of Option will become obvious. Coursera has a good Scala course .

Some of the uses:

  • chained calls where any call can return null
  • pattern matching

Jess Holle replied on Thu, 2014/05/08 - 8:01am

So why isn't it Serializable?  That just seems weird -- as you can't use it in any RMI call signatures for instance.  So if you think it's the best thing since sliced bread and use it everywhere, you have to change conventions any time you might be crossing any sort of boundary involving serialization.  Don't use RMI?  Well, servlet session data would be another fine example -- this has to be Serializable if it is to be replicated.  And so on.

And Optional is final, of course, so there's nothing one can do about this.

matt inger replied on Sat, 2014/05/10 - 10:24am

Optional has a ton of power in it.  It internally deals with nulls when you call methods like .map and .orElse.

Consider this code:

String s = "";
if (o != null) {
    s = o.toString();
}

It's ugly to have to do things like this.  Instead, you could to this with Optional:

String s= Optional.of(o).map(Object::toString).orElse("");

To me, the second one is much cleaner.  Plus as someone mentioned, the further down the chain you get, the more complex things can be, especially if each layer of a transformation like above could return null.  Let's say you had 3 transformations to do, and each one could result in a null value, you'd end with a 3 level nested if statement instead of:

Optional.of(o).map(f1).map(f2).map(f3).orElse("");

To me, the biggest issue with Optional is that due to backward compatibility, none of the collections classes (i'm looking at you Map), could not be retrofitted to used them.

Valery Silaev replied on Sat, 2014/05/10 - 6:45pm

Matt,

No, unfortunately your example is not clear to me, it has a lot of ceremony and simple old school null-check via ternary operator (?:) is more concise.

Where Optional may be useful is a signature of methods - both arguments and return value. It clearly shows whether or not null arguments are accepted or null may be returned.

I really like how similar feature is implemented in Ceylon from the ground up via union types. You have, for ex., "String" that is never null and "String?" that is in fact a syntactic sugar for the union type String|Nothing. And you have excellent compiler support that helps you branch your code on specific type from the union without clutter.

Compared to this , Java's Optional looks like an afterthought (and in fact it is) and a weak workaround that is sparsely used in RT lib itself. Rather than include Optional in Java runtime library, I would left it for third-party specialized libs (like Guava, Trove) where it will be used at consistently at least (unlike in Java collections).

Silviu Burcea replied on Tue, 2014/05/13 - 2:06am

I don't know why Optional.of even exists. It is clear that we may have a null value, that's why I'm using Optional, right?

Mario Fusco replied on Wed, 2014/05/14 - 7:14am

 The point is that you have no clue of how to use Optional. Maybe give a look at this article  to view an interesting example. Note that I wrote it 2 years ago and at time the Optional class didn't have a flatMap method, so I had to implement it on my own also to show its usefulness. Now you can develop that example using the Optional class shipped with Java 8.

Also give a look at this presentation from slide 12 to 24. It shows why you should use Optionals in your data model: to leverage the type system to clearly differentiate the values that can be missing (the car in the Person class and the insurance in the Car class in my example) from the ones that must be there (the name of the insurace company). In this way you know, through the type system, that a person without a car is acceptable in your data model while an insurance company without a name isn't.

Russell Bateman replied on Wed, 2014/05/14 - 7:15am

 After 25 years in C and then more than 6 years in Java, I don't know what I'd do with myself if I didn't handle null pointers (or objects). Since it's been a ubiquitous concern, solving it became long ago more or less a lower-motor function.

Pierre-yves Saumont replied on Wed, 2014/05/14 - 7:53am

 Optional is one of the many things that were made wrong in Java 8.

- It should of course be Serializable.

- Method of() is misleading. It does two things: Throwing an exception (if null) or returning an Optional (if not null). Use ofNullable() instead. But this is misleading, because it makes people think that the normal case is of() and ofNullable() is a special case.

- The real good with Option is that it allows composing functions not only when they return a value, but also when they would throw an exception or return a null pointer. Instead, the function returns an empty Option and this result may be composed with a another function. In other word, it allows transforming partial functions into total ones. However, this is not the only way to go. A better type system would also allow transforming partial functions into total ones by shrinking their domain. For example the square root function is partial on integers and would be total if returning an Optional (empty if the argument is negative). But the function would also be total if applied to non negative integers.

- The bad thing is we seldom need Option, because Option is good for cases where we should do nothing if there is no value. Much more useful is the Try monad that holds either a value or an exception, allowing composing function and carrying any exception until the end of the calculation.

It is very easy to write our own Try monad and use it in our programs. But the big problem is that we can't use it in public APIs because we would end with as many incompatible Try implementations as there are APIs!

Stuart Stephen replied on Wed, 2014/05/14 - 8:08am

Skip the Java 8 version and use Guava instead.

Brian Schlining replied on Wed, 2014/05/14 - 10:47am

Optional is a great tool to have in the toolbox. It can add great clarity to an API. For example, say you have a class that looks up something in a database and it may or may not find a return value. 

 
class SomeDAO { 
    public Optional<Foo> findFoo(someParams) { ... } 
} 

You could return null. But how does a develop know that ... oh yeah, they have to read the javadocs (if you remember to document it). With Optional, its clear that no value may be returned AND you can handle the returned Optional as a stream or monad, which as you get into functional programming, is simple and succinct.

Jess Holle replied on Wed, 2014/05/14 - 11:04am in response to: Brian Schlining

But the fact that Optional isn't Serializable would seem to place a very odd limitation on such a class.

Want to use Optional in the result of an RMI method?  Sorry, can't do that.  And so on.  It's hard to take Optional seriously if you know that if you do you'll have to be sure not to let it "trickle over" into such usages.  It's easier just to avoid it.

Brian Schlining replied on Wed, 2014/05/14 - 11:52am in response to: Jess Holle

I don't understand why everyone keeps bringing Serializable up. I don't use RMI, I don't use Serializable. In apps where we've tried to use Java serialization, we ALWAYS, ALWAYS end up ripping it out and using something else. These days, if I want to serialize objects, there's better, less JVM centric options (e.g. protocol buffers, JSON, Avro, MessagePack) Hell, even XML is better!

Jess Holle replied on Wed, 2014/05/14 - 12:07pm in response to: Brian Schlining

That's fine and good -- for you.

Making a core JVM class that's intended for use in formal APIs and making it non-Serializable and final so that it can't be used in such APIs is an inexplicable choice.

I suppose possibly someone wanted to force people to serialize T rather than Optional<T> in cases like distributable servlet session data, for instance.  That seems like a rather clumsy way to force folk to do the right thing here.

Brian Schlining replied on Wed, 2014/05/14 - 1:19pm in response to: Jess Holle

Just a thought ... How do you serialize an Optional when the contents may or may not be Serializable? If you constrain T so that it must be Serializable then you limit the usability of Optional. I see this as a deliberate design choice; I certainly wouldn't say it's inexplicable.



Valery Silaev replied on Wed, 2014/05/14 - 3:04pm in response to: Brian Schlining

Brian, 

We have no problems serializing Collections this way for more than 15 years :)

Brian Schlining replied on Wed, 2014/05/14 - 3:40pm in response to: Valery Silaev

Ha, good point ... just live dangerously! (As I mentioned, I don't use Java serialization anymore as it doesn't work for my use cases, so ... my bad.  :-) 

Also for the curious, I found this thread that gives more insight into what the developers were thinking: http://mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/thread.html#3186 

Jess Holle replied on Wed, 2014/05/14 - 3:46pm in response to: Brian Schlining

 And no less an expert than Eamonn McManus, asked why this made any sense whatsoever given behavior of RPC mechanisms that use Java Serialization, like RMI.

The entire thread gave no good answer for that.  The closest answer was Brian Goetz saying that making the object Serializable would have increased the maintenance costs for Optional.  Cry me a river.  One could easily implement readObject() and writeObject() methods that would produce a reasonable behavior while decoupling from the implementation details of Optional.  I get the feeling that those involved here simply didn't want things like RPC treading on their ivory tower.

Valery Silaev replied on Wed, 2014/05/14 - 4:15pm in response to: Jess Holle

Jess,

Fully agree with you. Serialization format for Optional is trivial: either null marker or serialized form of containing object ( that handles any serialization details on its own.). I.e. just what default serialization mechanism provides if authors would simply declare Optional as Serializable. No alternatives exist. No alternatives = no maintenance. I guess the true reason is that they just dislike adding public non-arg constructor to Optional.

Aleksey Novik replied on Wed, 2014/05/14 - 5:10pm

According to this mailing list ,  Optional was meant only as a return type in methods that might return null, and not being Serializable is intentional and as per design:

The JSR-335 EG felt fairly strongly that Optional should not be on any more than needed to support the optional-return idiom only.

Someone suggested maybe even renaming it to OptionalReturn ..."

Also  I wrote a post to summarize how Optional is meant to be used / not meant to be used. If used as intended it's still a useful thing to have, just not as powerful as in other languages. 
As said on the mailing list, maybe the name OptionalReturn would have been a better choice.


Raging Infernoz replied on Thu, 2014/05/22 - 5:27pm

I agree that nulls can be very annoying for stupid library code like the File directory listing methods which should have returned an object like an empty collection or array, rather than null; I've also seen Cowboy library code which should have thrown Exceptions for failed factory operations and never ever returned null; oh the air turned Blue with my cursing their carp design, because it caused nonsense NullPointerExceptions much later in code.

The main reason that NullPointerException, and other JVM Exceptions, are such a pain is because the JVM designers stupidly let it throw various Exceptions with no or inadequate messages and the stack trace doesn't reveal the in-their-face named or typed cause, so you have to guess; not impressed Sun & Oracle!

I fear that Optional will be abused by carp coders with methods which should never return Optional, but rather return null or throw an exception with a useful message, because this abuse could hide nasty missing value bugs much later in code.

Jess Holle replied on Wed, 2014/05/14 - 5:57pm in response to: Aleksey Novik

Yes, but being a generally permissible return type on methods, including RMI methods, requires that the the type be Serializable.

Thus they decided not to fully cover the ground they said they were going to cover.  That's what makes no sense.

Jess Holle replied on Wed, 2014/05/14 - 6:01pm in response to: Valery Silaev

Serializable doesn't require a public no-arg constructor.

Externalizable does -- but I wouldn't argue for that.

Of course if you go the readObject()/writeObject() route the internal field can't be final, so that's a downer.  But then you could just go with default serialization after all.  What's the mystery in the serialization here: it's writing a single T field, right?  Nothing more or less, ever.

Nathan Green replied on Wed, 2014/05/14 - 11:19pm

Meh. If NullPointerExceptions don't trouble you, you're either extremely fortunate or you do very uninteresting work. Just today I had to debug a NullPointerException that originated around 20 stack lines below where the failed dereference actually occurred. Something like a half-dozen separate libraries all happily passed a null argument along as if it were no big deal, until the program blew up. It was not fun, and it was not obvious why the same code worked on one machine but not another. Java's standard library cannot be saved due to backwards compatibility. However, languages that combine Optional with enforcement of non-null references can genuinely claim to have prevented a source of frustration and time-wasting for their users, and that is a valuable thing.

Mike Wilkes replied on Thu, 2014/05/15 - 1:42pm

 As others have pointed out, your usage pattern of Optional is flawed. One wouldn't generally use it after a method has returned Null.

Your getNullString() method would return an Optional<String> rather than a String.

Internally, it would either return a Optional.of("some string") or Optional.empty().

The caller can then use isPresent() on the returned object to see if a value was set.

The whole point of Optional is differentiating between a null being returned as 'there wasn't a value to be returned' for example from a search, and a null as in 'something went wrong, or wasn't supposed to be found or...'.


Makes the method signature explicitly state whether the caller can always expect an object, or may not always get an object without having to resort to nulls. A null would then be an error situation.

There is more potential power here.

To the poster that said use Guava instead, the Guava team has said they'll be removing their implementation of Optional as it is now in the core, and they only provide additional value.

Jess Holle replied on Thu, 2014/05/15 - 2:10pm in response to: Mike Wilkes

 Ah, but Guava got it right -- their Optional *is* Serializable.

So one can't use Java 8's Optional as a drop-in replacement for Guava's.

Pierre-yves Saumont replied on Thu, 2014/05/15 - 4:39pm in response to: Mike Wilkes

No, calling isPresent() is not the way Optional is intended to be used. Optional is a monad because it has a unit method (Optional.of()) and a flatMap() method. It is intended to be used mainly for composing functions returning Optional by chaining calls such as:

someOptional.flatMap(SomeClass::someMethodReturningOptional).flatMap(OtherClass::otherMethodReturningOptional).ifPresent(YetAnotherClass::yetAnotherMethod)

Methods that always return a value does not need to return Optional and must be composed with map() instead of flatMap().

The last method in the chain (yetAnotherMethod) is an "effect" taking the enclosed value (if present) and returning void. (In Java 8, effects are called Consumer).

isPresent() is there only to allow non functional developers to use Optional with the imperative paradigm.

Brian Schlining replied on Thu, 2014/05/15 - 5:31pm in response to: Jess Holle

Except, with the new lambda addition to Java 8. Guava's Optional is pretty anemic compared to Java 8's as it has no flatMap (or filter). See Pierre-yves Saumont's answer for more details.

Pierre-yves Saumont replied on Fri, 2014/05/23 - 3:01am in response to: Raging Infernoz

Yes, Optional will probably be abused because Optional is only meant to be used when the absence of value is not an error. Optional should NEVER be used to replace throwing an exception. Optional is meant to allow composing functions that may or may not return a value.

To compose functions that may return a value or throw an exception, we need an somethings else. In Scala, it is called Try, and like Optional, it is a monad.

For more information about the (absence of) Try monad in Java 8 (along with how to use the Optional monad), see my post What's Wrong in Java 8, Part IV: Monads

Brian Schlining replied on Fri, 2014/05/23 - 10:15am in response to: Pierre-yves Saumont

Very nice article.  I'm hopeful that the Try monad will eventually come to Java. After all, it is a relatively recent addition to Scala, only appearing since 2.10.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.