Optional 是 Java 8 引入的一个 容器类,用于表示 可能为 null 的对象,旨在减少空指针异常(NullPointerException)并提升代码的可读性。它通过提供一系列方法,允许开发者以声明式的方式处理可能缺失的值。


一、Optional 的核心方法

1. 创建 Optional 实例

Optional.of(T value)
  • 用途:创建一个包含非 null 值的 Optional
  • 注意:如果传入 null,会抛出 NullPointerException
Optional<String> optional = Optional.of("Hello");
Optional.ofNullable(T value)
  • 用途:创建一个可能为 null 的 Optional
  • 适用场景:当值可能为 null 时使用。
Optional<String> optional = Optional.ofNullable(getString());
Optional.empty()
  • 用途:创建一个空的 Optional
Optional<String> optional = Optional.empty();

2. 检查值是否存在

isPresent()
  • 用途:判断 Optional 中是否包含非 null 值。
if (optional.isPresent()) {
System.out.println(optional.get());
}
isEmpty()(Java 11+)
  • 用途:判断 Optional 是否为空(Java 11 引入)。
if (optional.isEmpty()) {
System.out.println("Value is absent");
}

3. 获取值

get()
  • 用途:获取 Optional 中的值。
  • 注意:如果值不存在,会抛出 NoSuchElementException
String value = optional.get(); // 可能抛出异常
orElse(T other)
  • 用途:如果值存在,返回该值;否则返回默认值。
String value = optional.orElse("Default");
orElseGet(Supplier<? extends T> supplier)
  • 用途:如果值存在,返回该值;否则调用 Supplier 生成默认值。
  • 适用场景:避免不必要的计算开销。
String value = optional.orElseGet(() -> computeDefaultValue());
orElseThrow()
  • 用途:如果值不存在,抛出异常(Java 10+)。
  • 自定义异常:可以传入异常工厂。
String value = optional.orElseThrow(() -> new MyException("Value not found"));

4. 转换与映射

map(Function<? super T, ? extends U> mapper)
  • 用途:对 Optional 中的值进行转换。
  • 注意:如果值为空,不会执行映射。
Optional<String> upper = optional.map(String::toUpperCase);
flatMap(Function<? super T, Optional<U>> mapper)
  • 用途:将 Optional<T> 转换为 Optional<U>
  • 适用场景:处理嵌套的 Optional
Optional<String> result = optional.flatMap(value -> findNestedValue(value));

5. 过滤

filter(Predicate<? super T> predicate)
  • 用途:根据条件过滤值。
  • 注意:如果值不存在或不满足条件,返回空 Optional
Optional<String> filtered = optional.filter(s -> s.length() > 5);

二、Optional 的链式操作

✅ 示例:嵌套对象处理

User user = getUser();
String name = Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.orElse("Unknown");

✅ 示例:避免空指针

Optional<String> result = Optional.ofNullable(getString())
.filter(s -> s.length() > 0)
.map(String::toUpperCase)
.orElse("DEFAULT");

三、Optional 与 Stream 的结合

✅ 将 Optional 转换为 Stream

List<String> list = Optional.ofNullable(getString())
.stream()
.collect(Collectors.toList());

✅ 处理多个 Optional

Optional<String> combined = Stream.of(
Optional.of("A"),
Optional.ofNullable(null),
Optional.of("B")
).flatMap(Function.identity())
.collect(Collectors.reducing((a, b) -> a + b));

四、最佳实践与注意事项

正确使用场景

  • 返回值:用于方法返回值,表示可能缺失的值。
  • 避免 null 检查:替代传统的 if (obj != null) 检查。
  • 链式调用:简化嵌套对象的处理。

错误使用场景

  • 方法参数:不要将 Optional 作为方法参数,这会增加调用者的复杂性。
  • 字段类型:不要用 Optional 作为类的字段类型。
  • 过度使用:对于简单逻辑,直接 null 检查可能更清晰。

五、完整示例代码

import java.util.Optional;

public class OptionalDemo {
public static void main(String[] args) {
// 创建 Optional
Optional<String> optional = Optional.ofNullable(getValue());

// 检查值是否存在
if (optional.isPresent()) {
System.out.println("Value: " + optional.get());
} else {
System.out.println("Value is absent");
}

// 获取默认值
String value = optional.orElse("Default");
System.out.println("Value: " + value);

// 转换值
Optional<String> upper = optional.map(String::toUpperCase);
upper.ifPresent(System.out::println);

// 过滤值
Optional<String> filtered = optional.filter(s -> s.length() > 5);
System.out.println("Filtered: " + filtered.orElse("Not long enough"));

// 处理嵌套 Optional
Optional<String> nested = optional.flatMap(OptionalDemo::findNested);
System.out.println("Nested: " + nested.orElse("Not found"));
}

private static String getValue() {
return "Hello";
}

private static Optional<String> findNested(String input) {
if ("Hello".equals(input)) {
return Optional.of("World");
}
return Optional.empty();
}
}

六、总结

方法 用途 注意事项
of() 创建非空 Optional 传入 null 会抛异常
ofNullable() 创建可能为 null 的 Optional 推荐用于不确定的值
isPresent() 检查值是否存在 ifPresent() 配合使用
orElse() 获取值或默认值 简化空值处理
map() / flatMap() 转换值 处理嵌套对象的利器
filter() 过滤值 简化条件判断
orElseThrow() 抛出异常 替代显式 null 检查

七、Optional 的优势与局限性

优势

  • 减少空指针异常:强制开发者处理可能缺失的值。
  • 提升代码可读性:用链式调用替代嵌套的 if-else
  • 函数式编程风格:与 Stream、Lambda 无缝集成。

局限性

  • 不适用于集合List<Optional<T>> 不如 List<T> 简洁。
  • 性能开销Optional 是对象包装,可能带来轻微性能损耗。
  • 过度设计:简单场景下可能增加代码复杂度。

通过合理使用 Optional,可以显著提升代码的健壮性和可维护性,但需注意避免滥用,保持代码的简洁与清晰。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐