Skip to content
清晨的一缕阳光
返回

Optional 深度解析

Optional 深度解析

Optional 是 Java 8 引入的空值处理工具,正确使用可以优雅地避免 NullPointerException。

一、为什么需要 Optional

1.1 空值问题

// 之前:嵌套 if 检查
public String getCity(User user) {
    if (user != null) {
        Address address = user.getAddress();
        if (address != null) {
            String city = address.getCity();
            if (city != null) {
                return city;
            }
        }
    }
    return "Unknown";
}

// Optional:链式调用
public String getCity(User user) {
    return Optional.ofNullable(user)
        .map(User::getAddress)
        .map(Address::getCity)
        .orElse("Unknown");
}

1.2 设计初衷

Optional 不是为了替代 null

而是提供一种更好的方式来处理可能为空的值

让空值检查更明确、更安全

二、创建 Optional

2.1 of() - 非空值

// 值不能为 null
Optional<String> opt = Optional.of("Hello");

// ❌ 会抛 NPE
Optional<String> opt = Optional.of(null); // NullPointerException

2.2 ofNullable() - 可为空

// 值可为 null
String value = getValue();
Optional<String> opt = Optional.ofNullable(value);

// 等价于
Optional<String> opt = value != null ? Optional.of(value) : Optional.empty();

2.3 empty() - 空 Optional

Optional<String> opt = Optional.empty();

// 单例模式
private static final Optional<Object> EMPTY = Optional.empty();

2.4 工厂方法返回 Optional

// 推荐:返回 Optional 而不是 null
public Optional<User> findById(Long id) {
    User user = dao.findById(id);
    return Optional.ofNullable(user);
}

// 使用
Optional<User> userOpt = service.findById(1L);

三、获取值

3.1 get() - 直接获取

Optional<String> opt = Optional.of("Hello");
String value = opt.get(); // "Hello"

// ❌ 危险:可能抛异常
Optional<String> empty = Optional.empty();
String value = empty.get(); // NoSuchElementException

// ✅ 先检查
if (opt.isPresent()) {
    String value = opt.get();
}

3.2 orElse() - 默认值

Optional<String> opt = Optional.ofNullable(getValue());

// 有值返回值,无值返回默认值
String result = opt.orElse("Default");

// 注意:默认值总是被计算
String result = opt.orElse(expensiveOperation()); // 即使有值也会执行

3.3 orElseGet() - 延迟计算

// 推荐:默认值延迟计算
String result = opt.orElseGet(() -> expensiveOperation());

// 只有当 Optional 为空时才执行

3.4 orElseThrow() - 抛异常

// 抛默认异常
String result = opt.orElseThrow(); // NoSuchElementException

// 抛自定义异常
String result = opt.orElseThrow(() -> 
    new BusinessException("USER_NOT_FOUND")
);

四、转换操作

4.1 map() - 值转换

Optional<User> userOpt = Optional.of(new User("Alice", 20));

// 转换值
Optional<String> nameOpt = userOpt.map(User::getName);

// 链式调用
Optional<String> cityOpt = userOpt
    .map(User::getAddress)
    .map(Address::getCity);

// 如果中间为 null,返回 empty

4.2 flatMap() - 扁平化

// map 返回嵌套 Optional
Optional<User> userOpt = Optional.of(new User());
Optional<Optional<String>> nested = userOpt.map(User::getCity);

// flatMap 扁平化
Optional<String> cityOpt = userOpt.flatMap(User::getCity);

// 场景:方法返回 Optional 时用 flatMap
public Optional<String> getCity(User user) {
    return Optional.ofNullable(user.getCity());
}

Optional<String> result = userOpt.flatMap(this::getCity);

4.3 filter() - 过滤

Optional<Integer> opt = Optional.of(10);

// 满足条件保留,否则返回 empty
Optional<Integer> result = opt.filter(n -> n > 5); // [10]
Optional<Integer> empty = opt.filter(n -> n > 20); // empty

五、判断操作

5.1 isPresent() - 是否有值

Optional<String> opt = Optional.of("Hello");

if (opt.isPresent()) {
    String value = opt.get();
    System.out.println(value);
}

5.2 isEmpty() - 是否为空(Java 11)

if (opt.isEmpty()) {
    System.out.println("No value present");
}

5.3 ifPresent() - 有值则执行

Optional<String> opt = Optional.of("Hello");

opt.ifPresent(value -> System.out.println(value));

// 方法引用
opt.ifPresent(System.out::println);

5.4 ifPresentOrElse() - Java 9

opt.ifPresentOrElse(
    value -> System.out.println("Value: " + value),
    () -> System.out.println("No value")
);

六、实战场景

6.1 数据库查询

// Repository
public Optional<User> findById(Long id) {
    return Optional.ofNullable(userMapper.selectById(id));
}

// Service
public String getUserName(Long id) {
    return userRepository.findById(id)
        .map(User::getName)
        .orElse("Unknown");
}

// 或者抛异常
public User getUser(Long id) {
    return userRepository.findById(id)
        .orElseThrow(() -> new UserNotFoundException(id));
}

6.2 配置读取

// 读取配置
public String getConfig(String key) {
    return Optional.ofNullable(configMap.get(key))
        .orElseGet(() -> loadDefaultConfig(key));
}

// 带类型转换
public Integer getIntConfig(String key) {
    return Optional.ofNullable(configMap.get(key))
        .map(Integer::parseInt)
        .orElse(100);
}

6.3 链式调用

public String getUserCity(User user) {
    return Optional.ofNullable(user)
        .map(User::getAddress)
        .flatMap(Optional::ofNullable)
        .map(Address::getCity)
        .orElse("Unknown");
}

6.4 集合处理

List<User> users = getUsers();

// 获取所有非空城市
List<String> cities = users.stream()
    .map(User::getAddress)
    .filter(Objects::nonNull)
    .map(Address::getCity)
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

// 使用 Optional
List<String> cities = users.stream()
    .map(u -> Optional.ofNullable(u.getAddress())
        .map(Address::getCity)
        .orElse(null))
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

6.5 方法参数

// ❌ 不推荐:Optional 作为参数
public void process(Optional<String> opt) {
    // ...
}

// ✅ 推荐:方法重载
public void process(String value) {
    process(Optional.ofNullable(value));
}

private void process(Optional<String> opt) {
    // 内部处理
}

七、最佳实践

7.1 推荐用法

// ✅ 作为返回值
public Optional<User> findById(Long id);

// ✅ 链式调用
Optional.ofNullable(user)
    .map(User::getName)
    .orElse("Unknown");

// ✅ 延迟计算
opt.orElseGet(() -> expensiveOperation());

// ✅ 抛异常
opt.orElseThrow(() -> new BusinessException("NOT_FOUND"));

7.2 避免用法

// ❌ 调用 get() 前不检查
String value = opt.get(); // 可能抛异常

// ❌ 作为字段
public class User {
    private Optional<String> name; // 不推荐
}

// ❌ 作为方法参数
public void process(Optional<String> opt) { // 不推荐
}

// ❌ 与 null 比较
if (opt == null) { // 错误
}

// ❌ 过度使用
Optional.ofNullable(value)
    .map(v -> Optional.ofNullable(v.trim()))
    .orElse(Optional.empty()); // 太复杂

7.3 性能考虑

// ❌ 创建过多 Optional 对象
Optional.ofNullable(a)
    .map(v -> Optional.ofNullable(b))
    .orElse(Optional.empty());

// ✅ 扁平化
Optional.ofNullable(a)
    .flatMap(v -> Optional.ofNullable(b));

八、总结

Optional 核心要点:

操作方法说明
创建of, ofNullable, empty根据场景选择
获取get, orElse, orElseGet, orElseThrow优先 orElseGet
转换map, flatMap, filter链式调用
判断isPresent, isEmpty, ifPresent避免直接 get

Optional 是处理空值的利器,但不是银弹,正确使用才能发挥价值。


分享这篇文章到:

上一篇文章
事务 ACID 特性详解
下一篇文章
索引优化实战案例