这个案例能让你学会用Java的Optional类避免空指针异常吗

wen java案例 42

本文目录导读:

这个案例能让你学会用Java的Optional类避免空指针异常吗

  1. 案例背景
  2. 第一步:用 Optional 改造查询结果
  3. 第二步:用 Optional 链式操作避免嵌套空检查
  4. 第三步:更复杂的场景 + 异常处理
  5. 完整示例对比
  6. 思考题

当然可以!下面通过一个实际案例,我会带你一步一步学会如何使用 Optional 避免空指针异常,并写出更优雅、安全的代码。


案例背景

假设我们要实现一个用户服务:根据用户ID查询用户,然后获取用户的 配送地址的城市名

典型“问题代码”(容易空指针)

public class UserService {
    public String getCityByUserId(Long userId) {
        User user = userRepository.findById(userId);
        // user 是 null —— 空指针!
        Address address = user.getAddress();
        // address 是 null —— 空指针!
        return address.getCity();
    }
}

这段代码在 useraddresscitynull 时,都会抛出 NullPointerException


第一步:用 Optional 改造查询结果

findById 返回 Optional<User>(这是最佳实践):

public Optional<User> findById(Long userId) {
    // ... 实际从数据库查询,可能返回 null
    return Optional.ofNullable(数据库返回的对象);
}

第二步:用 Optional 链式操作避免嵌套空检查

public String getCityByUserId(Long userId) {
    return userRepository.findById(userId)           // Optional<User>
            .map(User::getAddress)                   // Optional<Address>
            .map(Address::getCity)                   // Optional<String>
            .orElse("未知城市");                      // 如果任意一步为null,返回默认值
}

核心原理

  • map 方法:如果当前 Optional 有值,则执行函数并返回新 Optional;如果当前 Optional 为空,则直接返回空 Optional,不会执行函数 → 自然不会调用 null 的方法
  • orElse:当最终 Optional 为空时,提供默认值。

第三步:更复杂的场景 + 异常处理

如果遇到 null 时想抛出自定义异常而不是返回默认值:

public String getCityByUserIdOrThrow(Long userId) {
    return userRepository.findById(userId)
            .map(User::getAddress)
            .map(Address::getCity)
            .orElseThrow(() -> new RuntimeException("用户或地址信息不完整"));
}

完整示例对比

方式 代码 风险
❌ 传统方式 user.getAddress().getCity() 每一步都可能 NPE
✅ 使用 Optional .map(User::getAddress).map(Address::getCity).orElse("默认") 安全、简洁

  1. 返回 Optional 而不是 null:方法签名明确告诉调用者“可能没有值”。
  2. 多用 map / flatMap:优雅地处理链式调用。
  3. orElse / orElseGet / orElseThrow 处理无值情况:避免 if (x != null) 嵌套。
  4. 不要滥用:Optional 主要用于返回值不要用在字段、方法参数或集合中。

思考题

你会怎么用 Optional 处理下面这个更复杂的情况?

// 现有代码:潜藏多个 NPE
String countryName = user.getCompany().getAddress().getCountry().getName();

期待你的答案! 可以用 map 链式调用一行搞定。

学会了就点个赞吧 😊

抱歉,评论功能暂时关闭!