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)

相关链接