深入JDK中的Optional|京东云技术团队

2023年 8月 18日 72.2k 0

概述:

Optional最早是Google公司Guava中的概念,代表的是可选值。Optional类从Java8版本开始加入豪华套餐,主要为了解决程序中的NPE问题,从而使得更少的显式判空,防止代码污染,另一方面,也使得领域模型中所隐藏的知识,得以显式体现在代码中。Optional类位于java.util包下,对链式编程风格有一定的支持。实际上,Optional更像是一个容器,其中存放的成员变量是一个T类型的value,可值可Null,使用的是Wrapper模式,对value操作进行了包装与设计。本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。

1、解决的问题

臭名昭著的空指针异常,是每个程序员都会遇到的一种常见异常,任何访问对象的方法与属性的调用,都可能会出现NullPointException,如果要确保不触发异常,我们通常需要进行对象的判空操作。

举个栗子,有一个人(Shopper)进超市购物,可能会用购物车(Trolley)也可能会用其它方式,购物车里可能会有一袋栗子(Chestnut),也可能没有。三者定义的代码如下:

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
public class Shopper {
  private Trolley trolley;
  public Trolley getTrolley(){
    return trolley;
  }
}
public class Trolley {
  private Chestnut chestnut;
  public Chestnut getChestnut(){
     return chestnut;
  }
}
public class Chestnut {
  private String name;
  public String getName(){
    return name;
  }
}

这时想要获得购物车中栗子的名称,像下面这么写,就可能会见到我们的“老朋友”(NPE)

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
public String result(Shopper shopper){
  return shopper.getTrolley().getChestnut().getName();
}

为了能避免出现空指针异常,通常的写法会逐层判空(多层嵌套法),如下

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
public String result(Shopper shopper) {
        if (shopper != null) {
            Trolley trolley = shopper.getTrolley();
            if (trolley != null) {
                Chestnut chestnut = trolley.getChestnut();
                if (chestnut != null) {
                    return chestnut.getName();
                }
            }
        }
        return "获取失败辽";
    }

多层嵌套的方法在对象级联关系比较深的时候会看的眼花缭乱的,尤其是那一层一层的括号;另外出错的原因也因为缺乏对应信息而被模糊(例如trolley为空时也只返回了最后的获取失败。当然也可以在每一层增加return,相应的代码有会变得很冗长),所以此时我们也可以用遇空则返回的卫语句进行改写。

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
public String result(Shopper shopper) {
    if (shopper == null) {
        return "购物者不存在";
    }
    Trolley trolley = shopper.getTrolley();
    if (trolley == null) {
        return "购物车不存在";
    }
    Chestnut chestnut = trolley.getChestnut();
    if (chestnut == null) {
        return "栗子不存在";
    }
    return chestnut.getName();
}

为了取一个名字进行了三次显示判空操作,这样的代码当然没有问题,但是优秀的工程师们总是希望能获得更优雅简洁的代码。Optional就提供了一些方法,实现了这样的期望。

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
public String result(Shopper shopper){
  return Optional.ofNullable(shopper)
                .map(Shopper::getTrolley)
                .map(Trolley::getChestnut)
 .map(Chestnut::getName)
 .orElse("获取失败辽");
}

2、常用方法

1)获得Optional对象

Optional类中有两个构造方法:带参和不带参的。带参的将传入的参数赋值value,从而构建Optional对象;不带参的用null初始化value构建对象。

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
private Optional() {}
private Optional(T value) {}

但是两者都是私有方法,而实际上Optional的对象都是通过静态工厂模式的方式构建,主要有以下三个函数

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
public static  Optional of(T value) {}
public static  Optional ofNullable(T value) {}
public static  Optional empty() {}

创建一个一定不为空的Optional对象,因为如果传入的参数为空会抛出NPE

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
Chestnut chestnut = new Chestnut();
Optional opChest = Optional.of(chestnut);

创建一个空的Optional对象

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
Optional opChest = Optional.empty();

创建一个可空的Optional对象

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
Chestnut chestnut = null;
Optional opChest = Optional.ofNullable(chestnut);

2)正常使用

正常使用的方法可以被大致分为三种类型,判断类、操作类和取值类

P lainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPython
//判断类
public boolean isPresent() {}
//操作类
public void ifPresent(Consumer

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论