本文目录导读:

当然可以!下面通过一个实际案例,我会带你一步一步学会如何使用 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();
}
}
这段代码在 user、address 或 city 为 null 时,都会抛出 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("默认") |
安全、简洁 |
- 返回 Optional 而不是 null:方法签名明确告诉调用者“可能没有值”。
- 多用
map/flatMap:优雅地处理链式调用。 - 用
orElse/orElseGet/orElseThrow处理无值情况:避免if (x != null)嵌套。 - 不要滥用:Optional 主要用于返回值,不要用在字段、方法参数或集合中。
思考题
你会怎么用 Optional 处理下面这个更复杂的情况?
// 现有代码:潜藏多个 NPE String countryName = user.getCompany().getAddress().getCountry().getName();
期待你的答案! 可以用 map 链式调用一行搞定。
学会了就点个赞吧 😊