Optional<T> is a container that specifies "may or may not have a value" as type. When used in methods where the return value can be null, it forces the caller to never forget to check for null, reducing NPEs.
Learning Objectives
- Use
Optional.of/ofNullable/empty - Know
map/filter/orElse/orElseThrow/ifPresent - Learn the pattern of using Optional as return type
- Do not use Optional in antipatterns (fields, parameters, collection elements)
Key concepts
1) Create
Optional<String> a = Optional.of("hi"); //If null, NPE
Optional<String> b = Optional.ofNullable(maybe); //nullable
Optional<String> c = Optional.empty();
2) Retrieve value
String v = a.orElse("default");
String w = a.orElseThrow(() -> new IllegalStateException("None"));
a.ifPresent(System.out::println);
get() is not recommended because it throws an exception when the value is missing.
3) Transformation and filter
Optional<Integer> len = a.map(String::length);
Optional<String> upper = a.filter(s -> s.length() > 3).map(String::toUpperCase);
4) Anti-pattern
- Use of Optional as a field type
- Use Optional as parameter type
- Use Optional as collection element type
See as example
Example 1 — OptionalBasics.java: Create/Remove
import java.util.Optional;
public class OptionalBasics {
public static void main(String[] args) {
Optional<String> hi = Optional.of("hi");
Optional<String> empty = Optional.empty();
System.out.println(hi.isPresent());
System.out.println(empty.isPresent());
System.out.println(hi.orElse("default"));
System.out.println(empty.orElse("default"));
hi.ifPresent(s -> System.out.println("value=" + s));
empty.ifPresent(s -> System.out.println("Not running"));
}
}
Execution result
true
false
hi
default
value=hi
Note: ifPresent only executes lambda when there is a value.
Example 2 — OptionalMapFilter.java: Transformation/Filter Chaining
import java.util.Optional;
public class OptionalMapFilter {
public static void main(String[] args) {
Optional<String> name = Optional.of("Java");
Optional<Integer> len = name.map(String::length);
len.ifPresent(n -> System.out.println("length=" + n));
Optional<String> longName = Optional.of("hi")
.filter(s -> s.length() > 3)
.map(String::toUpperCase);
System.out.println("Long name?" + longName);
}
}
Execution result
length=4
Long name? Optional.empty
Memo: If filter is false, an empty Optional flows to the end of the chain.
Example 3 — OptionalReturn.java: used as return type
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class OptionalReturn {
static Map<String, Integer> ages = Map.of("exponent", 21, "Minsu", 25);
static Optional<Integer> findAge(String name) {
return Optional.ofNullable(ages.get(name));
}
public static void main(String[] args) {
System.out.println(findAge("exponent").orElse(-1));
System.out.println(findAge("unknown").orElse(-1));
findAge("Minsu").ifPresent(a -> System.out.println("Minsu=" + a));
}
}
Execution result
21
-1
Minsu=25
Memo: If Optional is used in the method return type, the caller will consciously handle null.
Example 4 — OrElseThrow.java: Exception when not present
import java.util.Optional;
public class OrElseThrow {
public static void main(String[] args) {
Optional<String> ok = Optional.of("value");
Optional<String> none = Optional.empty();
System.out.println(ok.orElseThrow());
try {
none.orElseThrow(() -> new IllegalStateException("Missing required value"));
} catch (IllegalStateException e) {
System.out.println("Exception:" + e.getMessage());
}
}
}
Execution result
value
Exception: Required value missing
Note: orElseThrow is often used with exceptions where the domain meaning is clear.
Common Mistakes
Optional.of(null)→ Immediate NPE. If there is a null possibility,ofNullable- Uncritical use of
get() - Field type Optional (conflicts with Serialization/JPA)
- Empty list
List<X>is more natural thanOptional<List<X>> - If you write Optional as if-else, its meaning disappears — Use of
map/orElsechaining
Cleanup
- Optional is best suited as return type
orElse/orElseThrow/ifPresentis safer thanget()- Remove if overlap with
map/filterchaining
Try it yourself
cd 05_Modern_Java/19_Optional/src
javac OptionalReturn.java
java OptionalReturn