Optional vs null — Where Each Belongs
Fast recall
Quick revision
Core answer
findById, findByEmail, getConfigValue). `null` remains appropriate for fields (especially in entities/DTOs), method parameters, collection elements, internal state, and private variables. This split follows Brian Goetz's (Oracle's Java architect) guidance: Optional was designed to communicate 'this method might return no value' at the type level, not to replace null wholesale. Using Optional as a field type wastes memory (every instance allocates an Optional wrapper), breaks serialization (Jackson/JPA don't natively support it), and adds ceremony without benefit. Using it as a method parameter is even worse — callers must wrap values just to call your method (doWork(Optional.of(x)) is ugly; simply overload or use @Nullable). Using it in collections is redundant — List> should be List with elements omitted or a Map> should be a Map with key absence signaling null. For nullable parameters and fields, prefer `@Nullable`/`@NonNull` annotations (JSR-305, Spring, or JSpecify) for static analysis without runtime cost, defensive null checks at API boundaries, or defaults at construction. The rule of thumb: return Optional; accept null; store null; never wrap null. And never return null from a method whose declared return type is Optional — that defeats the whole point.Whether the candidate knows Optional's proper scope (return types only), its anti-patterns (fields, parameters, collections), and the Brian Goetz guidance
Using Optional for fields (breaks serialization, wastes memory). Using Optional as method parameters (forces callers to wrap). Returning null from an Optional method
Cite Brian Goetz's Stack Overflow quote, explain why Optional is not Serializable, discuss JSpecify/JSR-305 annotations for parameter/field nullability, mention primitive variants (OptionalInt)
Interview-ready guide
Interview answer
The short version: Optional for return types where absence is valid; null (with @Nullable) for everything else. This follows Brian Goetz's guidance — he designed Optional specifically for return types, not to replace null wholesale.
Where Optional belongs
- Method return types:
findById,findByEmail,getConfigValue - Chaining:
opt.map(...).flatMap(...).orElse(...) - Signaling 'might be absent' in public APIs
- That's it
Where Optional is WRONG
1. Fields
- Not Serializable — breaks JPA, Jackson, Java serialization
- Wastes memory — 24–40 bytes per Optional wrapper, millions = pressure
- No benefit to callers (they don't see the field)
- Use
Discount+@Nullable, notOptional
2. Method parameters
- Forces callers to wrap:
doWork(Optional.of(x))is ugly - Worse than just accepting null
- Better: overload methods or use
@Nullableannotation
3. Collection elements
Listis redundant — use> Listand filter nullsMap— use> Map, absence via key
4. Collection returns
- Return
List.of()(empty), notOptional - Empty collections are idiomatic in Java
5. Record components
- Same reasoning as fields — serialization issues
Anti-patterns to avoid
Return null from Optional method
- Defeats the entire purpose
- Callers still have to null-check
- Return
Optional.empty()
Call .get() without guard
- Throws
NoSuchElementException - Use
.orElseThrow(...),.orElse(...),.ifPresent(...),.map(...).orElse(...)
Optional.of(maybeNull)
- Throws NPE if argument is null
- Use
Optional.ofNullable(...)for possibly-null sources
Better tools for non-return null handling
Nullability annotations
- JSpecify (new standard: Google/Oracle/JetBrains)
- JSR-305 (older:
@Nullable,@Nonnull) - Spring's
@Nullable - Compile-time / static analysis; zero runtime cost
- Flags mismatches in IDE, SonarQube, Error Prone
- Kotlin interop uses them
Objects.requireNonNull
- API boundary null checks
Objects.requireNonNull(email, "email required")- Fail-fast with clear message
Default values at construction
- Record compact constructors:
nickname = nickname != null ? nickname : email; - Builder pattern for many optional fields
Empty collection returns
List.of(),Set.of(),Map.of()- Better than null for 'no items'
Primitive Optionals
OptionalInt,OptionalLong,OptionalDouble- Avoid boxing overhead in hot paths
- Returned by
IntStream.max(),.average(), etc. - No map/flatMap; less ergonomic than
Optional
The idiomatic flow
- Repository returns
Optional - Service unwraps with
.orElseThrow,.map,.orElse - Controller returns the User (or lets exception become 404)
- Fields in entities: just
String email;(nullable if needed) - Internal state: just
null, maybe with@Nullable
Why not Kotlin-style non-null everywhere?
- Java's null is baked into JVM; can't banish
- Fields must be nullable for serialization, JPA, DI frameworks
- Accept it; use annotations and defensive checks
Recommendation: Follow the return-only rule: Optional is exclusively for method return types where absence is a legitimate outcome (repository finders, config lookups, parsing). Everywhere else — fields, parameters, collection elements, map values, internal state — use plain `null` with `@Nullable`/`@NonNull` annotations (prefer JSpecify for new code). Never return null from a method declared to return Optional; return Optional.empty(). Never call .get() without a guard; prefer .orElseThrow(...), .orElse(...), or .ifPresent(...). For collection returns, return empty collections (List.of()), never null. For hot-path primitives, use OptionalInt/OptionalLong/OptionalDouble to avoid boxing. Use `Objects.requireNonNull` at API boundaries for fail-fast null checks. Lean into Optional's chaining strength (.map().flatMap().orElse()) — this is where it shines over nested null checks. Don't try to eliminate null from Java entirely — that's what Kotlin is for; Java's job is to manage null pragmatically.
`Optional` vs `null` — Where Each Belongs
Direct Answer
Optional is the right choice only for method return types where the absence of a value is a valid, expected outcome (e.g., findById, findByEmail, getConfigValue). null remains appropriate for fields (especially in entities/DTOs), method parameters, collection elements, internal state, and private variables. This split follows Brian Goetz's (Oracle's Java architect) guidance: Optional was designed to communicate 'this method might return no value' at the type level, not to replace null wholesale. Using Optional as a field type wastes memory (every instance allocates an Optional wrapper), breaks serialization (Jackson/JPA don't natively support it), and adds ceremony without benefit. Using it as a method parameter is even worse — callers must wrap values just to call your method (doWork(Optional.of(x)) is ugly; simply overload or use @Nullable). Using it in collections is redundant — List<Optional<T>> should be List<T> with elements omitted or a Map<K, Optional<V>> should be a Map<K, V> with key absence signaling null. For nullable parameters and fields, prefer @Nullable/@NonNull annotations (JSR-305, Spring, or JSpecify) for static analysis without runtime cost, defensive null checks at API boundaries, or defaults at construction. The rule of thumb: return Optional; accept null; store null; never wrap null. And never return null from a method whose declared return type is Optional<T> — that defeats the whole point.
Common Mistakes & Pitfalls
Using Optional for fields (breaks serialization, wastes memory). Using Optional as method parameters (forces callers to wrap). Returning null from an Optional method
Check your understanding
Answer these without looking back at the article.
- Why shouldn't `Optional` be used as a field type?
- What's the difference between `Optional.of(x)` and `Optional.ofNullable(x)`?
- Why prefer `@Nullable` annotations over Optional for parameters?
- When is `OptionalInt` preferable to `Optional<Integer>`?
- What does Brian Goetz say about Optional's intended use?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.