19. Optional
`Optional<T>` is a container that **encodes "maybe a value, maybe none" in the type**. Using it as a return type for methods that might return null forces callers to handle the empty case and reduces NPEs.
What you'll learn
- 1Use `Optional.of` / `ofNullable` / `empty`
- 2Use `map` / `filter` / `orElse` / `orElseThrow` / `ifPresent`
- 3Use `Optional` as a **return type** pattern
- 4Avoid the anti-patterns (fields, parameters, collection elements)
Overview
`Optional<T>` is a container that **encodes "maybe a value, maybe none" in the type**. Using it as a return type for methods that might return null forces callers to handle the empty case and reduces NPEs.
Core Concepts
1) Creating
Optional<String> a = Optional.of("hi"); // NPE if null
Optional<String> b = Optional.ofNullable(maybe); // accepts null
Optional<String> c = Optional.empty();2) Extracting the value
String v = a.orElse("default");
String w = a.orElseThrow(() -> new IllegalStateException("missing"));
a.ifPresent(System.out::println);Avoid `get()` β it throws when the value is absent.
3) Transform and filter
Optional<Integer> len = a.map(String::length);
Optional<String> nonEmpty = a.filter(s -> !s.isEmpty());4) Anti-patterns
- Do **not** use `Optional` for fields, parameters, or collection elements
- Use only as a return type
5) Primitives
Use `OptionalInt` / `OptionalLong` / `OptionalDouble` for primitives to avoid boxing.
Examples
Example 1 β `Basic.java`
import java.util.Optional;
public class Basic {
public static void main(String[] args) {
Optional<String> a = Optional.of("hi");
Optional<String> b = Optional.empty();
System.out.println(a.orElse("default"));
System.out.println(b.orElse("default"));
a.ifPresent(s -> System.out.println("got " + s));
b.ifPresent(s -> System.out.println("never"));
}
}**Output**
hi
default
got hiExample 2 β `FindUser.java`
import java.util.Map;
import java.util.Optional;
public class FindUser {
static final Map<Integer, String> DB = Map.of(1, "Jisoo", 2, "Minsu");
static Optional<String> find(int id) {
return Optional.ofNullable(DB.get(id));
}
public static void main(String[] args) {
System.out.println(find(1).orElse("?"));
System.out.println(find(99).orElse("?"));
}
}**Output**
Jisoo
?Example 3 β `MapChain.java`
import java.util.Optional;
public class MapChain {
public static void main(String[] args) {
Optional<String> name = Optional.of(" Jisoo ");
int length = name.map(String::trim)
.map(String::length)
.orElse(0);
System.out.println("length=" + length);
}
}**Output**
length=5Example 4 β `OptionalThrow.java`
import java.util.Optional;
public class OptionalThrow {
public static void main(String[] args) {
try {
String s = Optional.<String>empty()
.orElseThrow(() -> new IllegalStateException("missing"));
System.out.println(s);
} catch (IllegalStateException e) {
System.out.println("error: " + e.getMessage());
}
}
}**Output**
error: missingCommon Mistakes
- Using `Optional` for fields β costs memory and clutters serialization
- Calling `get()` without checking β `NoSuchElementException`
- Wrapping a result that's never null in `Optional` β unnecessary noise
- Boxing primitives with `Optional<Integer>` instead of `OptionalInt`
- Chaining `Optional` so deep it's less readable than a `null` check
Summary
- `Optional` shines as a return type β it forces callers to handle the empty case
- Prefer `orElse` / `orElseThrow` over `get()`
- Don't use `Optional` for fields or parameters
Practice
# Practice - 19. Optional
## Exercise 1 β `findById`
- File: `Homework01.java`
- Key concepts: `Optional.ofNullable`, `orElse`
Requirements
- Lookup IDs 1, 2, 99 in a `Map`, print name or `unknown`.
Expected output
Jisoo
Minsu
unknown## Exercise 2 β Chain transformations
- File: `Homework02.java`
- Key concepts: `map`, `filter`
Requirements
- Take `Optional<String>` of `" hello "`, trim, uppercase, and print length or 0.
Expected output
length=5## Solutions After trying it yourself, compare with [`answer/`](./answer/).
Solution code (homework/answer/)
answer/Homework01.java
import java.util.Map;
import java.util.Optional;
/** findById. */
public class Homework01 {
static final Map<Integer, String> DB = Map.of(1, "Jisoo", 2, "Minsu");
static Optional<String> findById(int id) {
return Optional.ofNullable(DB.get(id));
}
public static void main(String[] args) {
int[] ids = {1, 2, 99};
for (int id : ids) System.out.println(findById(id).orElse("unknown"));
}
}
answer/Homework02.java
import java.util.Optional;
/** Chain transformations. */
public class Homework02 {
public static void main(String[] args) {
int len = Optional.of(" hello ")
.map(String::trim)
.map(String::toUpperCase)
.map(String::length)
.orElse(0);
System.out.println("length=" + len);
}
}
Try It Yourself
cd 05_modern/19_optional/src
javac MapChain.java
java MapChainNext Lecture
[20_Date_Time](../20_λ μ§_μκ°/) β handle dates and times with the modern `java.time` API.
All lecture materials and example code are openly available on GitHub.
View on GitHub β