Detailed explanation
Optional.of() and Optional.ofNullable() are static factory methods on java.util.Optional, introduced in Java 8. Both create an Optional containing the supplied value when that value is non-null. Their difference is how they handle null: Optional.of(null) throws a NullPointerException immediately, while Optional.ofNullable(null) returns Optional.empty(). An Optional represents either the presence of a non-null value or the absence of a value; it never contains null as a present value.
Use Optional.of(value) when a non-null value is required by your code's contract. For example, Optional<String> name = Optional.of("Anita") creates a present Optional. If the expression supplied to of() evaluates to null, construction fails at that point, making the violated assumption visible rather than treating it as normal absence. Under the hood, the construction path performs a null check using Objects.requireNonNull. This does not give compile-time null safety: a nullable variable can still be passed to of(), but a null value triggers a runtime exception.
Use Optional.ofNullable(value) when null is an expected possible result, such as when adapting a legacy lookup method. For example, Optional<String> name = Optional.ofNullable(findName(id)) contains the returned name if one exists and is empty if findName returns null. Internally, ofNullable checks the reference and selects either an empty Optional or an Optional containing the value. It does not catch exceptions: if findName(id) throws before returning, that exception still propagates. Also, an empty string is a non-null value, so Optional.ofNullable("") is present, not empty.
After creation, both methods produce the same Optional type, with the same operations for processing values and absence. For instance, name.orElse("Unknown") supplies a fallback, while name.map(String::toUpperCase) transforms a present value and leaves an empty Optional empty. Interviewers generally look for the exact null behaviour, an appropriate use case for each factory, and awareness that Optional does not automatically make all code null-safe. Choose of() to enforce a non-null assumption and ofNullable() to represent legitimate absence, rather than using either method mechanically.
Key points to remember
- Both factories return a present Optional for a non-null input.
- Optional.of(null) throws NullPointerException immediately.
- Optional.ofNullable(null) returns Optional.empty().
- Use of() for a required non-null value and ofNullable() for legitimate nullable input.
- An Optional cannot contain null as a present value; empty strings and empty collections are still present values.
Common mistakes candidates make
- Using Optional.of() on a possibly-null result while expecting an empty Optional.
- Assuming ofNullable() catches exceptions thrown while evaluating its argument.
- Calling get() without establishing presence, which can throw NoSuchElementException.
Likely follow-up questions
What happens if you call get() on Optional.empty()?
It throws NoSuchElementException. Prefer operations such as orElse(), orElseGet(), or orElseThrow(() -> new IllegalStateException("Missing value")) to express the intended handling.
What is the difference between orElse() and orElseGet()?
The argument to orElse() is evaluated even when the Optional is present. orElseGet() invokes its supplier only when the Optional is empty, making it suitable for expensive fallback computation.
Does Optional.ofNullable() flatten an existing Optional?
No; wrapping an Optional<String> produces an Optional<Optional<String>>, not a flattened result. If a mapping function already returns an Optional, use flatMap() instead of map() to avoid nesting.
Interview tip: State the null-handling difference first, show the two null examples, and explain when absence is expected versus a contract violation.
