Optional
Optional<T> 是 Java 8 引入的容器类,用于明确表达”值可能不存在”,避免 NullPointerException。
创建
// 确定有值
Optional<String> opt1 = Optional.of("hello");
// Optional.of(null) 会抛 NullPointerException
// 可能为 null
Optional<String> opt2 = Optional.ofNullable(getValue()); // 值为 null 时返回 empty
// 空
Optional<String> empty = Optional.empty();判断与取值
Optional<String> opt = Optional.of("hello");
// 是否有值
opt.isPresent(); // true
opt.isEmpty(); // false(Java 11+)
// 取值
opt.get(); // "hello",为空时抛 NoSuchElementException(避免直接用)
// 有值则执行
opt.ifPresent(s -> System.out.println(s));
opt.ifPresentOrElse( // Java 9+
s -> System.out.println("有值: " + s),
() -> System.out.println("为空")
);
// 获取值,为空时返回默认值
opt.orElse("default");
opt.orElseGet(() -> generateDefault()); // 惰性,为空时才调用
opt.orElseThrow(); // 为空时抛 NoSuchElementException
opt.orElseThrow(() -> new NotFoundException("not found"));转换与过滤
Optional<String> opt = Optional.of(" hello ");
// map:有值时转换,为空则传递 empty
Optional<Integer> length = opt.map(String::trim).map(String::length); // Optional[5]
// flatMap:转换结果本身就是 Optional(避免 Optional<Optional<T>>)
Optional<User> user = Optional.of("alice")
.flatMap(name -> userService.findByName(name)); // findByName 返回 Optional<User>
// filter:不满足条件则变为 empty
Optional<String> longStr = opt
.map(String::trim)
.filter(s -> s.length() > 3); // Optional["hello"]
// or:为空时切换到另一个 Optional(Java 9+)
Optional<User> result = findInCache(id).or(() -> findInDb(id));
// stream:转为 Stream(Java 9+,0 或 1 个元素)
opt.stream().forEach(System.out::println);链式调用替代 null 判断
// 传统写法(容易忘记判断)
String city = null;
if (user != null && user.getAddress() != null) {
city = user.getAddress().getCity();
}
// Optional 写法
String city = Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.orElse("未知");搭配 Stream 使用
// 过滤掉 empty,提取值(Java 9+)
List<Optional<String>> opts = List.of(
Optional.of("a"), Optional.empty(), Optional.of("b")
);
List<String> values = opts.stream()
.flatMap(Optional::stream) // 展平,过滤 empty
.toList(); // ["a", "b"]
// findFirst 返回 Optional
Optional<User> firstAdult = users.stream()
.filter(u -> u.getAge() >= 18)
.findFirst();
firstAdult.ifPresent(u -> System.out.println(u.getName()));与 Repository 结合(Spring Data)
// Repository 返回 Optional
Optional<User> userOpt = userRepository.findById(id);
// 找不到时抛业务异常
User user = userOpt.orElseThrow(
() -> new UserNotFoundException("用户不存在: " + id));
// 找不到时创建
User user = userOpt.orElseGet(() -> {
User newUser = new User(id, "默认用户");
return userRepository.save(newUser);
});注意事项
不要作为字段类型:Optional 不实现 Serializable,序列化会有问题。
// 不推荐
private Optional<String> name;
// 推荐,返回值用 Optional
public Optional<String> getName() {
return Optional.ofNullable(name);
}不要作为方法参数:参数可能为 null 本身就是设计问题,应当重载或明确语义。
// 不推荐
public void process(Optional<String> name) { }
// 推荐
public void process(String name) { } // 不允许 null
public void processOrDefault(String name) { } // 明确语义的重载orElse vs orElseGet:
// orElse:无论是否有值都会执行参数表达式
opt.orElse(expensiveCall()); // 有值也会调用 expensiveCall()
// orElseGet:只有为空时才执行,性能更好
opt.orElseGet(() -> expensiveCall()); // 有值时不调用速查
Optional.of(v) // 非 null 值
Optional.ofNullable(v) // 可能 null
Optional.empty() // 空
opt.isPresent() // 有值?
opt.isEmpty() // 无值?(Java 11)
opt.get() // 取值(避免直接用)
opt.orElse(def) // 有值取值,否则 def
opt.orElseGet(supplier) // 有值取值,否则调用 supplier
opt.orElseThrow(supplier) // 有值取值,否则抛异常
opt.ifPresent(consumer) // 有值则执行
opt.ifPresentOrElse(c, r) // 有值执行 c,否则执行 r(Java 9)
opt.map(fn) // 转换值
opt.flatMap(fn) // 转换为 Optional
opt.filter(pred) // 过滤
opt.or(supplier) // 为空时换另一个 Optional(Java 9)
opt.stream() // 转为 Stream(Java 9)