Optional 类

上一小节,我们接触到了Optional类,但没有详细展开介绍,Optional类也是 Java 8 新加入的类。本小节我们就来学习一下这个类,你将了解到Optional类的解决了什么问题,如何创建Optioanl类的对象,它又有哪些常用方法,如何在实际开发中应用Optional类等内容。

1. Optional 类概述

空指针异常(NullPointerExceptions)是 Java 最常见的异常之一,一直以来都困扰着 Java 程序员。一方面,程序员不得不在代码中写很多null的检查逻辑,让代码看起来非常臃肿;另一方面,由于其属于运行时异常,是非常难以预判的。
为了预防空指针异常,Google的Guava项目率先引入了Optional类,通过使用检查空值的方式来防止代码污染,受到Guava项目的启发,随后在Java 8中也引入了Optional类。
Optional 类位于java.util包下,是一个可以为 null 的容器对象,如果值存在则isPresent()方法会返回 true ,调用 get() 方法会返回该对象,可以有效避免空指针异常。下面我们来学习如何实例化这个类,以及这个类下提供了哪些常用方法。

2. 创建 Optional 对象

查看 java.util.Optional类源码,可以发现其构造方法是私有的,因此不能通过new关键字来实例化:
1.png
我们可以通过如下几种方法,来创建Optional 对象:

  • Optional.of(T t):创建一个 Optional 对象,参数 t 必须非空;
  • Optional.empty():创建一个空的Optional实例;
  • Optional.ofNullable(T t):创建一个Optional对象,参数t 可以为 null。

实例如下:

  1. import java.util.Optional;
  2. public class OptionalDemo1 {
  3. public static void main(String[] args) {
  4. // 创建一个 StringBuilder 对象
  5. StringBuilder string = new StringBuilder("我是一个字符串");
  6. // 使用 Optional.of(T t) 方法,创建 Optional 对象,注意 T 不能为空:
  7. Optional<StringBuilder> stringBuilderOptional = Optional.of(string);
  8. System.out.println(stringBuilderOptional);
  9. // 使用 Optional.empty() 方法,创建一个空的 Optional 对象:
  10. Optional<Object> empty = Optional.empty();
  11. System.out.println(empty);
  12. // 使用 Optional.ofNullable(T t) 方法,创建 Optional 对象,注意 t 允许为空:
  13. stringBuilderOptional = null;
  14. Optional<Optional<StringBuilder>> stringBuilderOptional1 = Optional.ofNullable(stringBuilderOptional);
  15. System.out.println(stringBuilderOptional1);
  16. }
  17. }

运行结果:

  1. Optional[我是一个字符串]
  2. Optional.empty
  3. Optional.empty

3. 常用方法

Optional类提供了如下常用方法:

  • booean isPresent():判断是否包换对象;
  • void ifPresent(Consumer<? super T> consumer):如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传递给它;
  • T get():如果调用对象包含值,返回该值,否则抛出异常;
  • T orElse(T other):如果有值则将其返回,否则返回指定的other 对象;
  • T orElseGet(Supplier<? extends T other>):如果有值则将其返回,否则返回由Supplier接口实现提供的对象;
  • T orElseThrow(Supplier<? extends X> exceptionSupplier):如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。

知道了如何创建Optional对象和常用方法,我们下面结合具体实例来看一下,Optional类是如何避免空指针异常的。
请查看如下实例,其在运行时会发生空指针异常:

  1. import java.util.Optional;
  2. public class OptionalDemo2 {
  3. static class Category {
  4. private String name;
  5. public Category(String name) {
  6. this.name = name;
  7. }
  8. public String getName() {
  9. return name;
  10. }
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14. @Override
  15. public String toString() {
  16. return "Category{" +
  17. "name='" + name + '\'' +
  18. '}';
  19. }
  20. }
  21. static class Goods {
  22. private String name;
  23. private Category category;
  24. public Goods() {
  25. }
  26. public Goods(String name, Category category) {
  27. this.name = name;
  28. this.category = category;
  29. }
  30. public String getName() {
  31. return name;
  32. }
  33. public void setName(String name) {
  34. this.name = name;
  35. }
  36. public Category getCategory() {
  37. return category;
  38. }
  39. public void setCategory(Category category) {
  40. this.category = category;
  41. }
  42. @Override
  43. public String toString() {
  44. return "Good{" +
  45. "name='" + name + '\'' +
  46. ", category=" + category +
  47. '}';
  48. }
  49. }
  50. /**
  51. * 获取商品的分类名称
  52. * @param goods 商品
  53. * @return 分类名称
  54. */
  55. static String getGoodsCategoryName(Goods goods) {
  56. return goods.getCategory().getName();
  57. }
  58. public static void main(String[] args) {
  59. // 实例化一个商品类
  60. Goods goods = new Goods();
  61. // 获取商品的分类名称
  62. String categoryName = getGoodsCategoryName(goods);
  63. System.out.println(categoryName);
  64. }
  65. }

运行结果:

  1. Exception in thread "main" java.lang.NullPointerException
  2. at OptionalDemo2.getGoodsCategoryName(OptionalDemo2.java:73)
  3. at OptionalDemo2.main(OptionalDemo2.java:80)

实例中,由于在实例化Goods类时,我们没有给其下面的Category类型的属性category赋值,它就为 null,在运行时, null.getName()就会抛出空指针异常。同理,如果goods实例为null,那么null.getCategory()也会抛出空指针异常。
在没有使用Optional类的情况下,想要优化代码,就不得不改写getGoodsCategoryName()方法:

  1. static String getGoodsCategoryName(Goods goods) {
  2. if (goods != null) {
  3. Category category = goods.getCategory();
  4. if (category != null) {
  5. return category.getName();
  6. }
  7. }
  8. return "该商品无分类";
  9. }

这也就是我们上面说的null检查逻辑代码,此处有两层if嵌套,如果有更深层次的级联属性,就要嵌套更多的层级。
下面我们将Optional类引入实例代码:

  1. import java.util.Optional;
  2. public class OptionalDemo3 {
  3. static class Category {
  4. private String name;
  5. public Category(String name) {
  6. this.name = name;
  7. }
  8. public String getName() {
  9. return name;
  10. }
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14. @Override
  15. public String toString() {
  16. return "Category{" +
  17. "name='" + name + '\'' +
  18. '}';
  19. }
  20. }
  21. static class Goods {
  22. private String name;
  23. private Category category;
  24. public Goods() {
  25. }
  26. public Goods(String name, Category category) {
  27. this.name = name;
  28. this.category = category;
  29. }
  30. public String getName() {
  31. return name;
  32. }
  33. public void setName(String name) {
  34. this.name = name;
  35. }
  36. public Category getCategory() {
  37. return category;
  38. }
  39. public void setCategory(Category category) {
  40. this.category = category;
  41. }
  42. @Override
  43. public String toString() {
  44. return "Good{" +
  45. "name='" + name + '\'' +
  46. ", category=" + category +
  47. '}';
  48. }
  49. }
  50. /**
  51. * 获取商品的分类名称(使用 Optional 类包装)
  52. * @param goods 商品
  53. * @return 分类名称
  54. */
  55. static String getGoodsCategoryName(Goods goods) {
  56. // 将商品实例包装入 Optional 类,创建 Optional<Goods> 对象
  57. Optional<Goods> goodsOptional = Optional.ofNullable(goods);
  58. Goods goods1 = goodsOptional.orElse(new Goods("默认商品", new Category("默认分类")));
  59. // 此时 goods1 一定是非空,不会产生空指针异常
  60. Category category = goods1.getCategory();
  61. // 将分类实例包装入 Optional 类,创建 Optional<Category> 对象
  62. Optional<Category> categoryOptional = Optional.ofNullable(category);
  63. Category category1 = categoryOptional.orElse(new Category("默认分类"));
  64. // 此时 category1 一定是非空,不会产生空指针异常
  65. return category1.getName();
  66. }
  67. public static void main(String[] args) {
  68. // 实例化一个商品类
  69. Goods goods = null;
  70. // 获取商品的分类名称
  71. String categoryName = getGoodsCategoryName(goods);
  72. System.out.println(categoryName);
  73. }
  74. }

运行结果:

  1. 默认分类

实例中,我们使用Optional类的 ofNullable(T t)方法分别包装了goods对象及其级联属性category对象,允许对象为空,然后又调用了其ofElse(T t)方法保证了对象一定非空。这样,空指针异常就被我们优雅地规避掉了。

4. 对于空指针异常的改进

Java 14 对于空指针异常有了一些改进,它提供了更明确异常堆栈打印信息,JVM 将精确地确定那个变量是null,不过空指针异常依然无法避免。明确的异常堆栈信息,能够帮助开发者快速定位错误发生的位置。

5. 小结

通过本小节的学习,我们知道了 Optional 类主要用于应对 Java 中的空指针异常,它是一个可以为 null 的容器对象,我们可以通过Optional类下的几个静态方法来创建对象。另外,我们也结合实例介绍了如何使用Optional类来规避空指针异常,实例中还有很多其他没用到的 API,希望大家可以自己研习。

若有收获,就点个赞吧

0 人点赞

  • 书签
  • 添加书签 移除书签
  • Java入门教程
    • Java 简介与安装配置
      • 在 Windows 上安装 Java
      • 第一个 Java 程序
      • Java 集成开发环境 - IntelliJ IDEA
    • Java 基础
      • Java 数组
      • Java 基础语法
      • Java 变量
      • Java 基本数据类型
      • Java 运算符
      • Java 表达式、语句和块
      • Java 条件语句
      • Java 循环语句
      • Java 字符串
    • Java 面向对象
      • Java 方法
      • Java 类和对象
      • Java 封装
      • Java 继承
      • Java 多态
      • Java 抽象类
      • Java 接口
      • Java 内部类
      • Java 包
    • Java 进阶
      • Java String类
      • Java StringBuilder 类
      • Java Scanner 类
      • Java 异常处理
      • Java 包装类
      • Java 枚举类
      • Java 集合
      • Java 泛型
      • Java 反射
      • Java 注解
      • Java 输入输出流
      • Java 序列化与反序列化
      • Java 日期和时间
      • Java 多线程
      • Java 数据库编程
      • Java 8新特性
      • Lambda 表达式
      • 函数式接口
      • 方法引用
      • Java 流式操作
      • Optional 类
    • 实战
      • 实战 - 需求分析
      • 实战 - 数据库设计
      • 实战 - 业务实现 1
      • 实战 - 业务实现 2
  • Java Web 基础
    • XML 入门
      • XML 文档结构
      • XML 语义约束
      • XML 文档解析及 XPath 语言
    • Servlet 入门
      • 软件结构初识
      • Tomcat环境搭建
      • 使用IDEA创建Servlet程序
      • 我的第一个Servlet
      • Servlet中的Get与Post
      • 附录:IDEA配置Web相关问题解决方案
    • JSP 入门
      • JSP 入门
  • 设计模式入门教程
    • 设计模式简介
    • 创建型模式:关注对象创建过程
      • 单例模式
      • 工厂模式
      • 抽象工厂模式
    • 结构型模式:关注类和对象组合
      • 代理模式
      • 适配器模式
      • 装饰者模式
    • 行为型模式:关注对象间的通信过程
      • 策略模式
      • 模版方法模式
      • 观察者模式
  • Maven入门教程
    • Maven 基础知识
      • Maven 简介
      • Maven 安装与配置
      • Maven POM 模型
      • Maven 的依赖
      • Maven 仓库
      • Maven 生命周期
      • Maven 版本管理
      • Maven 的聚合与继承
    • Maven 基本使用
      • Maven 多模块构建
      • Maven 单元测试
      • Maven 使用 Profile 构建
      • Maven 生成站点
      • Maven 属性与资源过滤
    • 画外音
      • Maven 私服搭建
      • Maven 编写插件
      • Maven Archetype 原型
      • Maven 对接 IDE 使用
暂无相关搜索结果!
    展开/收起文章目录

    玻璃钢生产厂家湖南玻璃钢雕塑厂中牟正规的玻璃钢雕塑商场女装专柜美陈玻璃钢雕塑 工艺品江门玻璃钢雕塑销售价格收购玻璃钢雕塑福建玻璃钢卡通雕塑查询河南花朵玻璃钢仿铜雕塑国庆商场户外美陈玉林玻璃钢泡沫雕塑公司玻璃钢红色雕塑价格重庆特色玻璃钢雕塑优势玻璃钢熊猫雕塑安装方案枣庄小品系列玻璃钢雕塑安装青岛玻璃钢雕塑工厂山东周年庆典商场美陈报价文山市玻璃钢雕塑设计供应重庆仿铜玻璃钢雕塑价位漳州园林玻璃钢雕塑报价玻璃钢店门口雕塑新乡不锈钢人物玻璃钢卡通雕塑河南常用商场美陈供应商河北定做玻璃钢牛雕塑南平玻璃钢仿铜雕塑价格镂空玻璃钢景观雕塑生产厂家新余多彩玻璃钢雕塑订做价格玻璃钢肖恩羊卡通雕塑吕梁玻璃钢海豚雕塑厂家徐州玻璃钢雕塑厂家报价玻璃钢卡通人物雕塑价格香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

    玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化