48 | 用 Optional 消灭 NPE但别把它当万能药摘要Optional的设计目的是让返回值可能为空这件事显式化而不是消灭所有null。滥用Optional反而让代码更难读。一、问题现象// ❌ 滥用把 Optional 当字段类型classUser{privateOptionalStringemail;// 不推荐}// ❌ 滥用把 Optional 当方法参数publicvoidprocess(OptionalOrderorder){...}// 不推荐正确用法Optional只适合作为返回类型告诉调用方可能没有值。二、踩坑现场场景 1用Optional.get()不判断// ❌ 错误和直接 null 判断没区别OptionalUseruseruserService.findById(1L);Useruuser.get();// ❌ 如果是 empty抛 NoSuchElementException场景 2为了用 Optional 而用// ❌ 不推荐多此一举OptionalStringnameOptional.ofNullable(user.getName());if(name.isPresent()){Stringnname.get();}// ✅ 直接判断反而更清晰if(user.getName()!null){Stringnuser.getName();}三、正确写法3.1 作为返回类型推荐// ✅ 正确返回值用 Optional显式告诉调用方可能为空publicOptionalUserfindById(Longid){UseruseruserMapper.selectById(id);returnOptional.ofNullable(user);// 可能为空}// 调用方OptionalUseruserOptuserService.findById(1L);userOpt.ifPresent(u-process(u));// 有值才处理3.2 提供默认值// ✅ orElse() — 无论是否有值都执行括号里的代码StringnameOptional.ofNullable(user.getName()).orElse(未知);// ✅ orElseGet() — 只有没值时才执行推荐StringnameOptional.ofNullable(user.getName()).orElseGet(()-getDefaultName());// 区别orElseGet 是懒加载有值时不会调 getDefaultName()3.3 链式调用// ✅ 推荐链式调用代码清晰StringcityOptional.ofNullable(user).map(User::getAddress).map(Address::getCity).orElse(未知);// 中间任何一步为 null都返回 未知不会 NPE四、最佳实践✅ Optional 使用的 4 条铁律只作为返回类型不要作为字段类型或方法参数不要用get()而不判断用isPresent()或ifPresent()链式调用map/flatMap/filter是 Optional 最优雅的用法orElseGet()比orElse()好懒加载不浪费计算 不要用 Optional 的场景场景推荐写法字段类型直接用原类型JPA/Hibernate 不支持 Optional 字段方法参数直接用原类型多个参数用 Builder集合类型用空集合Collections.emptyList()不用OptionalList五、小结Optional只适合做返回类型显式表达可能为空不要当字段类型或方法参数用链式调用是 Optional 最优雅的用法map/flatMap/filterorElseGet()比orElse()好懒加载调用get()前必须用isPresent()判断下一篇预告序列化版本号 serialVersionUID 不写会怎样—— 不写 JVM 会自动生成但不同 JVM 实现可能不一样反序列化会失败。