Optional.of() and Optional.ofNullable()
Wrap a value in an Optional, choosing of() when null is a bug and ofNullable() when null means the value is genuinely absent.
public static <T> Optional<T> of(T value)
public static <T> Optional<T> ofNullable(T value)- Added in Java Java 8
Parameters
| Parameter | Type | Description |
|---|---|---|
$value | T | The value to wrap. Must not be null for of(); may be null for ofNullable(). |
Return value
Optional<T>of() returns an Optional holding the given non-null value. ofNullable() returns an Optional holding the value, or an empty Optional if the value is null.
Errors
Optional.of throws NullPointerException if value is null. Optional.ofNullable never throws.
Optional is a container that holds either one non-null value or nothing. Its main job is to be the return type of a method that might not have an answer, such as findById, so the caller cannot forget the not-found case. The two factory methods differ only in how they treat null.
Which one to call
Optional.of(value) requires a value. Passing null throws NullPointerException immediately. Use it when you have just created or checked the value and a null there would mean a bug in your own code; the exception points straight at it.
Optional.ofNullable(value) accepts null and turns it into Optional.empty(). Use it at the edges where null is the normal way older APIs say "not there": Map.get, HttpServletRequest.getHeader, a nullable database column, System.getenv.
Optional<User> findById(long id) {
return Optional.ofNullable(usersById.get(id)); // Map.get returns null when missing
}Mistakes people make
- Calling
Optional.of(map.get(key)). It works in every test with known keys, then throws in production the first time a key is missing. If the value can be absent, it isofNullable. - Returning
nullfrom a method declared to returnOptional. Callers will chain.map(...)and get aNullPointerExceptionon the Optional itself. ReturnOptional.empty()instead. - Using
Optionalfor fields, method parameters or collection elements. It is notSerializable, it adds an allocation, and an empty list or a nullable parameter says the same thing more simply. Keep it for return values.
Back-end angle
Repository and service methods that look one thing up are the natural home for Optional. Spring Data's findById returns Optional<T> for exactly this reason. A controller then turns the empty case into a 404 with orElseThrow, rather than every layer checking for null. For primitives there are OptionalInt, OptionalLong and OptionalDouble, which avoid boxing.
Example
When to use it
- Returning the result of a repository lookup by id so the controller must decide what a missing row means.
- Wrapping an optional HTTP header or query parameter read from a map that returns null for missing keys.
- Turning a nullable database column or environment variable into a value that can be defaulted or validated in one chain.
Frequently asked questions
What is the difference between Optional.of and Optional.ofNullable?
Optional.of(value) throws NullPointerException if value is null, so it is for values that must exist. Optional.ofNullable(value) returns Optional.empty() for null and is for values that may legitimately be missing.
Why does Optional.of throw a NullPointerException?
Because you passed it null. Optional.of is designed to fail fast when a value you claim is present is not. If null is a normal outcome, such as a missing map key, use Optional.ofNullable instead.
Should I use Optional as a method parameter or field?
Generally no. Optional was designed as a return type. It is not Serializable, so it does not suit entity or DTO fields, and an Optional parameter forces callers to wrap values. Overloads or a nullable parameter with a clear contract are simpler.
More examples
Wrapping a request header that may be missing
Map.get returns null for a missing header, and ofNullable turns that into an empty Optional so orElse can supply a fallback. With Optional.of the second call would throw.
String requestId(Map<String, String> headers) {
return Optional.ofNullable(headers.get("X-Request-Id"))
.orElse("generated-0001");
}
void main() {
IO.println(requestId(Map.of("X-Request-Id", "abc-123")));
IO.println(requestId(Map.of("Accept", "application/json")));
}
// Output:
// abc-123
// generated-0001Using of() when the value is known to exist
Integer.parseInt never returns null, so of() is the honest choice there; the empty cases are handled explicitly with Optional.empty(). This is the shape of a typical parse-or-nothing helper for configuration values.
Optional<Integer> parsePort(String raw) {
if (raw == null || raw.isBlank()) {
return Optional.empty();
}
try {
return Optional.of(Integer.parseInt(raw.strip()));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
void main() {
IO.println(parsePort("8080"));
IO.println(parsePort(" 9000 "));
IO.println(parsePort("abc"));
IO.println(parsePort(null));
}
// Output:
// Optional[8080]
// Optional[9000]
// Optional.empty
// Optional.emptyEquality, hashCode and toString
Two Optionals are equal when both are empty or both hold equal values, regardless of which factory made them. The hash code is the value's hash code, or 0 when empty.
void main() {
Optional<String> a = Optional.of("json");
Optional<String> b = Optional.ofNullable("json");
Optional<String> none = Optional.ofNullable(null);
IO.println(a.equals(b));
IO.println(none.equals(Optional.empty()));
IO.println(Optional.of(42).hashCode() + " " + none.hashCode());
IO.println(a + " " + none);
}
// Output:
// true
// true
// 42 0
// Optional[json] Optional.empty
Discussion