BackendBench
Coffee

Unravel › Java concepts › Generics and functional

Java language

Optional and null safety

Optional<T> is a box that holds a value or nothing.

Learn these first

At a glance

Mental model

A parcel that might be empty.

What happens, in order
  1. 1Create with Optional.of(x) (x must not be null), Optional.ofNullable(x) or Optional.empty()
  2. 2Unwrap safely: orElse(default), orElseGet(() -> compute()), orElseThrow(() -> new NotFound()), ifPresent(x -> ...)
  3. 3Transform without unwrapping: map(User::getEmail), filter(e -> e.endsWith("@x.com")), flatMap(...)
Remember
Watch out
get() without checkingorElse with an expensive callOptional as a parameter or fieldWrapping then immediately calling isPresent() and get(), which is just a null check with extra steps
Example (highlighted lines explain it)
Optional<User> user = repo.findByEmail(email);String name = user.map(User::getName).orElse("guest");user.ifPresent(u -> log.info("found {}", u.getId()));
  1. line 1 uses Optional, the core of Optional and null safety
  2. line 2 uses orElse, the core of Optional and null safety
  3. line 3 uses ifPresent, the core of Optional and null safety
Read the full explanation (about 1 min)

Optional<T> is a box that holds a value or nothing. Returning it from a method tells the caller "this may be absent" and forces them to decide what to do, instead of risking a surprise NullPointerException.

A mental model

A parcel that might be empty. You open it and say what to do in both cases: "if there is a gift, use it; otherwise use this default".

How it works

Create with Optional.of(x) (x must not be null), Optional.ofNullable(x) or Optional.empty().

Unwrap safely: orElse(default), orElseGet(() -> compute()), orElseThrow(() -> new NotFound()), ifPresent(x -> ...).

Transform without unwrapping: map(User::getEmail), filter(e -> e.endsWith("@x.com")), flatMap(...).

Going deeper

orElse(expensive()) always evaluates its argument, even when a value is present; use orElseGet for anything costly or with side effects.

get() on an empty Optional throws, so calling it without isPresent() just moves the null problem. Prefer orElseThrow with a meaningful exception.

Optional is meant for return values. Do not use it for fields, method parameters or collections (return an empty list, not Optional<List>).

Under the hood

Optional is a final value-based class with a single nullable field; empty() returns one shared instance. It adds one small object allocation, which the JIT can often remove.

Common mistakes

  • get() without checking.
  • orElse with an expensive call.
  • Optional as a parameter or field.
  • Wrapping then immediately calling isPresent() and get(), which is just a null check with extra steps.

How Unravel recognises it

When you paste code, Unravel looks for these signs of optional and null safety. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Optional and null safety?

Optional<T> is a box that holds a value or nothing. Returning it from a method tells the caller "this may be absent" and forces them to decide what to do, instead of risking a surprise NullPointerException.

What are the most common mistakes with Optional and null safety?

get() without checking. orElse with an expensive call. Optional as a parameter or field. Wrapping then immediately calling isPresent() and get(), which is just a null check with extra steps.

How can I see Optional and null safety in real code?

Paste your own Java into Unravel and it will point out where optional and null safety appears, explain how it works at the detail level you choose, and draw the flow of the code around it.