【一】避免空指针的通用方法
✅ 1️⃣ 设计阶段:避免产生 null
-
领域模型里避免「nullable」属性
-
构造函数里要求非空
✅ 示例
public User(String name) {
this.name = Objects.requireNonNull(name, "name must not be null");
}
✅ 2️⃣ 静态检查
-
注解
-
@Nonnull,@Nullable -
Checker Framework / ErrorProne / SpotBugs
-
✅ 示例
public String process(@Nonnull String input) { return input.trim(); }
✅ 3️⃣ 运行时保护
-
Objects.requireNonNull()
✅ 4️⃣ 语言级增强
-
Java 14+: 增强的 NPE 异常信息
-
默认开启(Java 16+)
-
-XX:+ShowCodeDetailsInExceptionMessages
-
✅ 输出示例
Cannot invoke "Address.getCity()" because "person.getAddress()" is null
✅ 5️⃣ Null Object 模式
避免返回 null,用无害对象表示「空行为」
✅ 示例
class NullLogger implements Logger {
public void log(String msg) { /* do nothing */ }
}
✅ 6️⃣ Optional
Java 8+ 的核心改进:明确表达「可能缺失」
✅ 语义
-
Optional 返回值 → 明确可为空
-
避免调用者遗漏 null 检查
✅ 基本用法
Optional<User> findById(String id) {
return Optional.ofNullable(repo.get(id));
}
【二】Optional 最佳实践
✅ ① 适用场景
✅ 用于方法返回值
-
表示查询、解析、计算 可能没有结果
✅ 示例
Optional<User> findUserById(String id);
❌ ② 不推荐场景
❌ 参数
void setUser(Optional<User> user); // 不推荐
原因说明:
-
违背设计初衷:
Optional被设计为返回值容器,用于避免 null 返回值,不是为参数设计。 -
调用不便:需要额外封装,降低可读性
-
不能传 null:如果传
null,会抛NullPointerException,如Optional.of(null)。 -
不利于重载方法设计:Java 编译器类型擦除后会导致签名冲突
✅ 用
void setUser(@Nullable User user);
❌ 类字段
class User {
Optional<Address> address; // 不推荐
}
原因说明:
-
违反 JavaBean 规范:Optional没有实现序列化接口导致序列化报错,标准 JavaBean 属性期望
getX()返回具体值而不是容器。EL 表达式(如 JSP/Thymeleaf)访问user.name只会得到 Optional 实例。 -
ORM 不支持:实体字段使用
Optional会抛出MappingException或无法映射。 -
Jackson/Gson 无法正确序列化/反序列化
-
运行时额外开销:每次访问字段都需要
.get()、.isPresent(),代码冗长。
✅ 用
class User {
@Nullable Address address;
}
然后在 getter 中返回 Optional
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
❌ 集合
Optional<List<User>> getUsers(); // 不推荐
原因说明:
-
设计冗余:集合天然支持元素缺失或为空的语义。
-
处理繁琐
-
泛型复杂度提升:组合类型如
Map<String, Optional<List<String>>>可读性极差
✅ 直接返回空集合
List<User> getUsers();
✅ ③ 创建 Optional
Optional.of(value) // value != null
Optional.ofNullable(value) // 允许 value 为 null
Optional.empty()
✅ ④ 消费值
optional.ifPresent(u -> sendEmail(u.getEmail()));
✅ ⑤ 默认值
String result = optional.orElse("default");
String lazy = optional.orElseGet(() -> computeDefault());
✅ ⑥ 抛异常
User user = optional.orElseThrow(() -> new NotFoundException());
✅ ⑦ 链式变换
Optional<Address> address = userOpt.map(User::getAddress); Optional<String> city = userOpt.map(User::getAddress).map(Address::getCity);
✅ ⑧ 过滤
optional.filter(u -> u.isActive())
✅ ⑨ Java 9+ 扩展
optional.or(() -> otherOptional);
optional.ifPresentOrElse( val -> process(val), () -> handleAbsent() );
✅ ⑩ 避免 get()
⚠️ 反模式
String s = optional.get(); // 潜在 NPE
✅ 推荐
optional.orElse(...) optional.orElseThrow(...)
总结
✅ 方法返回值 → Optional 表示「可无」
✅ 参数 → 不用 Optional,直接 @Nullable
✅ 字段 → 不用 Optional,用普通类型 + @Nullable
✅ 集合返回值 → 返回空集合,不要包 Optional
✅ 使用链式 map / flatMap / filter
✅ 消费时用 orElse / orElseThrow / ifPresent
1167

被折叠的 条评论
为什么被折叠?



