当前位置: 首页 > news >正文

【Java踩坑笔记】48_用Optional消灭NPE,但别把它当万能药

48 | 用 Optional 消灭 NPE,但别把它当万能药

摘要Optional的设计目的是让返回值"可能为空"这件事显式化,而不是消灭所有null。滥用Optional反而让代码更难读。


一、问题现象

// ❌ 滥用:把 Optional 当字段类型classUser{privateOptional<String>email;// 不推荐}// ❌ 滥用:把 Optional 当方法参数publicvoidprocess(Optional<Order>order){...}// 不推荐

正确用法Optional只适合作为返回类型,告诉调用方"可能没有值"。


二、踩坑现场

场景 1:用Optional.get()不判断

// ❌ 错误:和直接 null 判断没区别Optional<User>user=userService.findById(1L);Useru=user.get();// ❌ 如果是 empty,抛 NoSuchElementException

场景 2:为了用 Optional 而用

// ❌ 不推荐:多此一举Optional<String>name=Optional.ofNullable(user.getName());if(name.isPresent()){Stringn=name.get();}// ✅ 直接判断反而更清晰if(user.getName()!=null){Stringn=user.getName();}

三、正确写法

3.1 作为返回类型(推荐)

// ✅ 正确:返回值用 Optional,显式告诉调用方"可能为空"publicOptional<User>findById(Longid){Useruser=userMapper.selectById(id);returnOptional.ofNullable(user);// 可能为空}// 调用方:Optional<User>userOpt=userService.findById(1L);userOpt.ifPresent(u->process(u));// 有值才处理

3.2 提供默认值

// ✅ orElse() — 无论是否有值,都执行括号里的代码Stringname=Optional.ofNullable(user.getName()).orElse("未知");// ✅ orElseGet() — 只有没值时才执行(推荐)Stringname=Optional.ofNullable(user.getName()).orElseGet(()->getDefaultName());// 区别:orElseGet 是懒加载,有值时不会调 getDefaultName()

3.3 链式调用

// ✅ 推荐:链式调用,代码清晰Stringcity=Optional.ofNullable(user).map(User::getAddress).map(Address::getCity).orElse("未知");// 中间任何一步为 null,都返回 "未知"(不会 NPE)

四、最佳实践

✅ Optional 使用的 4 条铁律

  1. 只作为返回类型,不要作为字段类型或方法参数
  2. 不要用get()而不判断,用isPresent()ifPresent()
  3. 链式调用(map/flatMap/filter)是 Optional 最优雅的用法
  4. orElseGet()orElse()(懒加载,不浪费计算)

🔍 不要用 Optional 的场景

场景推荐写法
字段类型直接用原类型,JPA/Hibernate 不支持 Optional 字段
方法参数直接用原类型,多个参数用 Builder
集合类型用空集合(Collections.emptyList()),不用Optional<List>

五、小结

  • Optional只适合做返回类型,显式表达"可能为空"
  • 不要当字段类型或方法参数用
  • 链式调用是 Optional 最优雅的用法(map/flatMap/filter
  • orElseGet()orElse()好(懒加载)
  • 调用get()前必须用isPresent()判断

下一篇预告:序列化版本号 serialVersionUID 不写会怎样?—— 不写 JVM 会自动生成,但不同 JVM 实现可能不一样,反序列化会失败。

http://www.jsqmd.com/news/1203212/

相关文章:

  • 2026年7月最新亨得利官方服务项目及价格查询|维修地址及24小时电话权威信息通告 - 亨得利官方
  • 【智能体开发】《LangChain核心技术与LLM项目实践》_198.[第12章 项目实战] 追踪前沿技术:arXiv论文阅读与前沿算法复现
  • IS200WREAS1A 终端板
  • 计算机毕业设计之基于jsp抑郁症测试系统的设计与实现
  • 2026年枣庄水磨石瓷砖厂商优质合作企业盘点参考 - 热点品牌推荐
  • Cesium离线部署实战:从数据下载到本地服务发布全流程
  • Czkawka终极指南:如何高效清理重复文件释放磁盘空间
  • 告别繁琐点击:用智能脚本轻松管理你的京东日常任务
  • PCSX2模拟器性能调优:5个场景化解决方案与深度优化指南
  • IFC++:C++开源库实现BIM数据处理与可视化开发指南
  • 2026年7月最新亨得利官方服务项目及价格查询|地址及电话权威信息通告 - 亨得利官方博客
  • 美妆集合实体店如何把到店流量沉淀为会员?餐宝盈小程序+GEO打法解析,含零代码SAAS、AI编程、源码定制
  • Cursor调试效率提升300%的私密工作流:自定义error-parser脚本、实时AST可视化面板与错误聚类看板(附GitHub仓库)
  • 2026 年广州军事训练营推荐:军博营地业内领先 - 松梢月冷
  • Windows本地智能体一键部署:OpenClaw 5分钟落地实践
  • 高可靠性线路板识别与应用指南
  • 第1课:FastAPI|简介、核心优势、技术生态与整体学习路线
  • Operator 部署:从概念到实践
  • 基于51单片机与GSM的远程电子告示牌系统设计
  • 佛山青少年训练营推荐:军博营地实力顶尖 - 秋山寄远
  • 亲身探访深圳江诗丹顿官方售后服务中心|维修地址及售后热线(2026年7月最新) - 江诗丹顿官方服务中心
  • jiuwen-deepsearch核心功能详解:规划-检索-反思三合一智能工作流
  • C++并行分布式系统实战:从数据分解到MPI+OpenMP混合编程
  • 硬件工程师知识体系与核心技能全解析
  • 如何快速上手PvZ2 Gardendless:免费Web版植物大战僵尸2完整指南
  • C++实现摩斯电码转换器:从std::map到字符串处理的综合实践
  • Ubuntu下C++项目集成ONNX Runtime:从源码编译到模型推理验证全流程
  • 【Java踩坑笔记】49_序列化版本号serialVersionUID不写会怎样?
  • 【Atlas】HBase 表设计对 Atlas 性能有何影响?如何调优?
  • 相似度检索:原理、算法与应用实践