Skip to content

Instantly share code, notes, and snippets.

@durgaswaroop
Last active October 5, 2023 12:00
Show Gist options
  • Save durgaswaroop/cf6a6f6ce90a27830e451a8f28e91921 to your computer and use it in GitHub Desktop.
Save durgaswaroop/cf6a6f6ce90a27830e451a8f28e91921 to your computer and use it in GitHub Desktop.
Java Optional usage and Best practices
  • Optional.empty() - An empty optional
  • Optional.of(t) - returns a present Optional containing t. (t must be non-null)
  • Optional.ofNullable(t) - returns an Optional with t that can be null

Rules

  1. Never return null from a method that's supposed to return an optional. It defeats the purpose of Optional
  2. Never do opt.get() unless you can prove that the optional is present.
  3. Prefer alternatives to using opt.isPresent() followed by opt.get()
  4. It's generally a bad idea to create an Optional for the sole purpose of chaining methods from it to get a value.
  5. If an Optional chain is nested or has an intermediate result of Optional<Optional>, it is probably too complex.

Good practices

orElse family

  1. orElse(default) - Returns value if present or else a default value
    Optional<Data> opt = ....
    Data data = opt.orElse(DEFAULT_VALUE)
    
  2. orElse(supplier) - Returns value if present or else gets a default value by calling a supplier
    Optional<Data> opt = ....
    Data data = opt.orElseGet(Data::new)
    
  3. orElseThrows(exSupplier) - Returns value if present or else throws an exception obtainer from a supplier
    Optional<Data> opt = ....
    Data data = opt.orElseThrows(IllegalStateException::new)
    

map()

Optional<Customer> opt = ....

Instead of doing, return opt.isPresent() ? opt.get().getName() : "UNKNOWN"

Use map to do, return opt.map(Customer::getName().orElse("UNKNOWN");

If the value is present, map() transforms or maps the value into another value and returns the result in an optional.

If value is not present, it returns an empty Optional.

The mapper function is called on the value only when it is present.

Examples:

Optional.of(10).map(x -> x + 10) ===> Optional.of(20)

Optional.empty().map(x -> x + 10) ===> Optional.empty()

flatMap()

Like map() but transforms the value inside an optional using a functions that returns an optional (x -> Optional.of(x)).

Examples:

Optional.of(10).flatMap(x -> Optional.of(x + 10)) ===> Optional.of(20)

Optional.empty().flatMap(x -> Optional.of(x + 10)) ===> Optional.empty()

filter()

Optional<Configuration> oParent = config.parent()

Code:

if (!oParent.isPresent() || oParent.get() != this.config()) {
    throw new IllegalArgumentException()
}

That can be replaced with filter as follows:

config.parent.filter(config -> config == this.config()).orElseThrow(IllegalArgumentException::new)

ifPresent()

Optional<Task> oTask = getTask(....)

Instead of doing this:

if(oTask.isPresent()) {
    executor.runTask(oTask.get());
}

Do:

getTask(...).ifPresent(task -> executor.runTask(task))

Or better:

getTask(...).ifPresent(executor::runTask)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment