Skip to content

Instantly share code, notes, and snippets.

@MikeChristianson
Created March 2, 2018 18:05
Show Gist options
  • Save MikeChristianson/f5c12d9caa682b2ba7db4659997f6768 to your computer and use it in GitHub Desktop.
Save MikeChristianson/f5c12d9caa682b2ba7db4659997f6768 to your computer and use it in GitHub Desktop.
Java's Optional

Optional<T>

Mike Christianson

^ Added in Java 8 (2014)

^ Optional is a solution to a problem. The problem of null. But, what is null?


The meanings of null

  • Uninitialized value (intentional)
  • Uninitialized value (accidental)
  • Invalid
  • Error condition
  • Value not present

^ These are just the semantic problems. There are other problems, like "what is a null, even?"


null is a bummer

  • Not a part of the type system
    • A null String for example, has the same type as a non-null String
  • Surfaces as a runtime problem
    • It may take a production run to encounter a NullPointerException

^ For these reasons -- this ambiguity -- null has been called a Billion Dollar Mistake.


Billion Dollar Mistake

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. … I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. -- Tony Hoare


Optional<T>

What is it Good For?

  • Value not present
  • Part of the type system
  • Surfaces problem at compile-time

But, it is not a replacement for null. Sorry, I lied earlier.

^ Java had no way to force the handling the absence of something. You had to explicitly check for null just to be sure something was there. That sometimes lead to bad programming practices, complex, difficult to read code, or overly-defensive programming. ^ Optional<T> is a type and so the type system, and therefore the compiler, is used to enforce the correct behavior. ^ Reminiscent of returning empty collections instead of null collections


How to use Optional

Creation

public <Thing> find(criteria) {
  Thing thing = doTheWorkToFindTheThing();
  return thing; //btw, it might be null lol
}

public Optional<Thing> safeFind(criteria) {
  Thing thing = find(criteria);
  return Optional.ofNullable(thing); //may be present
}

^ If you're writing a library method that returns a null to indicate no value present, instead return Optional.ofNullable(). Your callers will now have to handle the case where a value is not present.


How to use Optional

Consuming

Optional<Thing> thingy = thingFinder.safeFind(criteria);

Thing thing = thingy.orElse(defaultThing);

How to use Optional

Consuming

Optional<Thing> thingy = thingFinder.safeFind(criteria);

Thing thing = thingy.orElseGet(() -> supplier::computeThing);

How to use Optional

Consuming

Optional<Thing> thingy = thingFinder.safeFind(criteria);

Thing thing = thingy.orElseThrow(RuntimeException::new);

How to use Optional

Consuming

Optional<Thing> thingy = thingFinder.safeFind(criteria);

thingy.ifPresent(this::doIt);

How to use Optional

Consuming

Optional<Thing> thingy = thingFinder.safeFind(criteria);

Optional<Other> otherThing = thingy.map(this::transformIt);

Use as Directed

Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors. -- Brian Goetz


Do Not Use

For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list. You should almost never use it as a field of something or a method parameter. -- Brian Goetz


Potential Usage Matches Intended Use
Library method return types representing "no result"
Returning an array of results
Returning a list of results
Field of something
Method parameter
Local variable

Generally avoid

Optional.ofNullable(t).orElse(default)
Optional.ofNullable(t).ifPresent(this:doIt);

It's generally a bad idea to create an Optional for the specific purpose of chaining methods from it to get a value. -- Stuart Marks


Don't use Optional everywhere

Remember, Optional is a box!

  • consumes 16 bytes
  • is a separate object (potentially adds GC pressure)
  • always requires a dependent load, leading to cache misses
  • a single Optional is OK, but if you litter your data structures with many Optional instances, it could easily turn into a performance problem -- Stuart Marks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment