Java Optional的判空操作详解

目录
  • Optional判空
    • 代码模拟
    • Optional常用方法
    • 使用Optional一定比null好吗
    • Optional 使用场景

Optional判空

JAVA在1.8版本推出Optional,官方文档将其描述为可能包含或不包含非空值的容器对象,目前Optional用于避免程序出现异常NullPointerException。

代码模拟

// 下面所有类省略set,get方法
public class Employee {
    private String employeeName;
    private Team team;
}

public class Team {
    private String teamName;
    private Department department;

    public Team(String teamName) {
        this.teamName = teamName;
    }
}

public class Department {
    private String departmentName;
    private Company company;
}

public class Company {
    private String companyName;
}

测试代码

// 在创建时因为没有初始化Team对象的Department属性,导致后续调用空指针
public void testCompany(){
    Employee employee = new Employee();
    employee.setEmployeeName("zhangsan");
    employee.setTeam(new Team("xxx产品组"));
    System.out.println(employee.getTeam().getDepartment().getCompany().getCompanyName());
}

这时如果我们采用传统方式一般判空代码如下

public void testCompanyAvoidNPE(){
    Employee employee = new Employee();
    employee.setEmployeeName("zhangsan");
    employee.setTeam(new Team("xxx产品组"));
    Team team = employee.getTeam();
    if (team == null){
        System.out.println("异常拉,参数为空!");
        return;
    }
    Department department = team.getDepartment();
    if (department == null){
        System.out.println("异常拉,参数为空!");
        return;
    }
    Company company = department.getCompany();
    if (company == null){
        System.out.println("异常拉,参数为空!");
        return;
    }
    String companyName = company.getCompanyName();
    System.out.println(companyName);
}

显然这种判空代码造成了业务代码膨胀,代码可读性极低,所以在这种场景下我们需要学习1.8推出的判空容器对象Optional。

Optional常用方法

创建 Optional 对象

JAVA提供了三个静态方法用于构建Optional对象如下所示

返回值 方法和描述
static <T> Optional<T> empty()  返回一个空的 Optional实例。
static <T> Optional<T> of(T value)  返回具有 Optional的当前非空值的Optional。
static <T> Optional<T> ofNullable(T value)  返回一个 Optional指定值的Optional,如果非空,则返回一个空的  Optional 。
public void createOptionalObject(){
    System.out.println(Optional.empty());
    // 传null报空指针
    // System.out.println(Optional.of(null));
    System.out.println(Optional.of(new String("1111")));
    // 传null调用Optional.empty()
    System.out.println(Optional.ofNullable(null));
    System.out.println(Optional.ofNullable(new Content("111","测试内容")));
}

class Content {
    private String id;
    private String value;

    public Content() {
    }

    public Content(String id, String value) {
        this.id = id;
        this.value = value;
    }
    // 省略get,set方法
}

执行结果如下

Optional.empty
Optional[1111]
Optional.empty
Optional[Content{id='111', value='测试内容'}]

在真正使用时建议使用ofNullable,因为它能处理空值或者非空值,代码如下

public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

常用功能方法

方法名 返回值 功能描述
isPresent() boolean 判断Optional对象是否存在,存在true不存在false
ifPresent(Consumer<? super T> consumer) void 如果Optional对象存在执行consumer消费型接口,不存在不执行
get T 返回Optional对象封装的对象T数据,注意实际对象可能为空会抛出异常
orElse(T other) T 如果Optional对象存在则返回封装的对象数据,如果不存在返回T other数据,相当于不存在给默认值
orElseGet(Supplier<? extends T> other) T 是orElse方法的升级版,区别在于orElse方法传入的是一个固定默认值,而此方法是一个供给型函数方法,如果Optional对象为空则执行other的方法逻辑
orElseThrow(Supplier<? extends X> exceptionSupplier) <X extends Throwable>T 一样是orElse方法的升级版,当Optional对象为空执行exceptionSupplier方法,最后抛出异常
filter(Predicate<? super T> predicate) Optional<T> 当Optional对象满足predicate断言函数中的匹配规则则返回,否则返回空Optional
map(Function<? super T,? extends U> mapper) <U> Optional<U> 能够将Optional的对象值处理转换为另一个实例对象值,并生成新类型的Optional对象,如果生成的新对象为null,则返回一个空Optional对象
flatMap(Function<? super T,Optional<U>> mapper) <U> Optional<U> 和map类似,不过map操作的是具体对象,而flatMap返回的是Optional封装过的对象

代码演示如下

    public void testOptionFunction(){
        //===============================isPresent()================================
        // false
        System.out.println(Optional.empty().isPresent());
        // Optional[Content{id='222', value='测试'}]
        System.out.println(Optional.ofNullable(new Content("222","测试")));

        //===============================ifPresent()================================
        // 不为空打印:Content{id='222', value='测试'}  为空不执行
        Optional.ofNullable(new Content("222","测试")).ifPresent(e->{
            System.out.println("不为空打印:"+e);
        });

        //===============================get()================================
        // NoSuchElementException: No value present
        try {
            System.out.println(Optional.empty().get());
        }catch (Exception e){
            e.printStackTrace();
        }
        // Content{id='222', value='测试'}
        System.out.println(Optional.ofNullable(new Content("222","测试")).get());

        //===============================orElse()================================
        // Content{id='0', value='默认'}
        System.out.println(Optional.empty().orElse(new Content("0","默认")));

        //===============================orElseGet()================================
        // Content{id='333', value='测试orElseGet'}
        System.out.println(Optional.empty().orElseGet(() -> {
            Content content = new Content("333", "测试orElseGet");
            return content;
        }));

        // Content{id='222', value='测试'}
        System.out.println(Optional.ofNullable(new Content("222", "测试")).orElseGet(() -> {
            Content content = new Content("444", "测试orElseGet");
            return content;
        }));

        //===============================orElseThrow()================================
        // java.lang.Exception: 参数为空
        try {
            Optional.empty().orElseThrow(()->{
               return new Exception("参数为空");
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

        //===============================filter()================================
        // "555".equals(e.getId());   Optional[Content{id='555', value='测试'}]
        // "5565".equals(e.getId());  Optional.empty
        System.out.println(Optional.ofNullable(new Content("555", "测试")).filter(e -> {
            return "5565".equals(e.getId());
        }));
    }

map和flatMap

public void testOptionMapFunction(){
    Optional<Content> optionalContent = Optional.ofNullable(new Content("777","测试Map"));

    Optional<Content> optionalContent1 = optionalContent.map(e -> {
        String id = e.getId();
        String value = e.getValue();
        return e;
    });

    Optional<Content> optionalContent2 = optionalContent.flatMap(e -> {
        String id = e.getId();
        String value = e.getValue();
        // 不同点在这里,一个是可以转换为另一个实例对象,一个是转换为Optional包装对象
        return Optional.of(e);
    });
    // 最终效果实现效果类似
    System.out.println(optionalContent1);
    System.out.println(optionalContent2);
}

使用Optional一定比null好吗

这个显然是不对的,如果使用方式如下所示,其实和null的直接判空没有区别

public static void main(String[] args) {
    Optional<Content> optionalContent = Optional.ofNullable(null);
    // 直接报错
    optionalContent.get();
}

// 升级写法
public static void main(String[] args) {
    Optional<Content> optionalContent = Optional.ofNullable(null);
    // 非空判断
    if (optionalContent.isPresent()){
        System.out.println(optionalContent.get());
    }
}

null的直接判空

public static void main(String[] args) {
    Content content = new Content();
    if (content != null){
        System.out.println(content);
    }
}

正确写法如下所示

public static void main(String[] args) {
    Optional<Content> optionalContent = Optional.ofNullable(null);
    // 非空时执行消费型接口里面的逻辑
    optionalContent.ifPresent(content -> {
        System.out.println(content);
    });
}

到这里有人可能说,如果if{}else{}里面都需要写逻辑如何处理呢

public static void main(String[] args) {
    Optional<Content> optionalContent = Optional.ofNullable(null);
    Content content = optionalContent.map(e -> {
        // 做一些业务
        // 返回值可以为任意类型值,可以返回字符串,不过orElseGet需要返回字符串保持一致即可
        return e;
    }).orElseGet(() -> {
        // 做一些业务
        return new Content("0", "默认值");
    });
    System.out.println(content);
}

Optional 使用场景

减少繁琐的非空判断

如前面提到的testCompanyAvoidNPE方法中的例子,就可以采用Optional来简化

public void testCompanyAvoidNPE2(){
    Employee employee = new Employee();
    employee.setEmployeeName("zhangsan");
    employee.setTeam(new Team("xxx产品组"));
    // 这里相当于是链式操作
    String companyName = Optional.ofNullable(employee)
        .map(employee1 -> employee1.getTeam())
        .map(team -> team.getDepartment())
        .map(department -> department.getCompany())
        .map(company -> company.getCompanyName())
        .orElse("no company");
    System.out.println(companyName);
}

设置默认值兜底

// 原始方法
public String setDefaultValue1(Content content){
    if (ObjectUtils.isEmpty(content)){
        return "0";
    }
    if (StringUtils.isEmpty(content.getId())){
        String id = "0";
        content.setId(id);
    }
    return content.getId();
}

// 采用Optional
public String setDefaultValue2(Content content){
    String id = Optional.ofNullable(content)
        .map(content1 -> content1.getId())
        .orElse("0");
    return id;
}

Optional 尽量只用作方法的返回类型

注意我们采用Optional的最终目的是避免程序中出现null对象异常的情况,所以我们封装方法的时候可以采用Optional 作为方法的返回值类型,但也要注意Optional虽好但不要滥用,适当使用即可。

以上就是Java Optional的判空操作详解的详细内容,更多关于Java Optional判空操作的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java如何使用Optional与Stream取代if判空逻辑(JDK8以上)

    通过本文你可以用非常简短的代码替代业务逻辑中的判null校验,并且很容易的在出现空指针的时候进行打日志或其他操作. 注:如果对Java8新特性中的lambda表达式与Stream不熟悉的可以去补一下基础,了解概念. 首先下面代码中的List放入了很多Person对象,其中有的对象是null的,如果不加校验调用Person的getXXX()方法肯定会报空指针错误,一般我们采取的方案就是加上if判断: public class DemoUtils { public static void main(

  • Java函数式开发 Optional空指针处理

    摘要 空闲时会抽空学习同在jvm上运行的Groovy和Scala,发现他们对null的处理比早期版本Java慎重很多.在Java8中,Optional为函数式编程的null处理给出了非常优雅的解决方案.本文将说明长久以来Java中对null的蹩脚处理,然后介绍使用Optional来实现Java函数式编程. 那些年困扰着我们的null 在Java江湖流传着这样一个传说:直到真正了解了空指针异常,才能算一名合格的Java开发人员.在我们逼格闪闪的java码字符生涯中,每天都会遇到各种null的处理,

  • Java8 Optional判空详解(简化判空操作)

    一.导语 在没有用Optional判空之前,你是否也像下面的代码一样判空呢?如果是,请往下看,Optional 相对传统判空的优势. 传统阶层判空 为什么要用Optional,它到底是什么东西 你也看到了上面的那张图,一旦代码量大起来了,条件多了,代码就会变得很冗余,变得难以维护.那么此时我们就有必要了解Optional了. Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象.Optional 是个容器:它可以

  • Java8的Optional如何干掉空指针(示例详解)

    Optional概述 Optional 是个容器:它可以保存类型T的value,或者仅仅保存null.Optional提供很多有用的方法,这样我们就不用显式进行空值检测,很好地解决了空指针异常处理的问题,比如可以使用isPresent()方法判断value是否为null,使用get()方法获取value值等等. Optional的构造方法是私有的,实例不能new,可以使用静态方法来创建: // 1.创建一个包装对象值为空的Optional对象 Optional<String> optStr =

  • Java利用Optional解决空指针异常

    目录 背景介绍 案例 基本用法解析 转换与过滤 案例优化 源码解析 总结 背景介绍 Java 8 引入了一个十分实用的 Optional 类,它主要是为了解决空指针异常(NullPointerException).当我们对对象的属性进行检查,判断它的值是否为期望的格式,最终却发现我们查看的并不是一个对象,而是一个空指针,它会立即抛出一个让人厌烦的 NullPointerException 异常. 本质上,Optional 类是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象

  • Java Optional的判空操作详解

    目录 Optional判空 代码模拟 Optional常用方法 使用Optional一定比null好吗 Optional 使用场景 Optional判空 JAVA在1.8版本推出Optional,官方文档将其描述为可能包含或不包含非空值的容器对象,目前Optional用于避免程序出现异常NullPointerException. 代码模拟 // 下面所有类省略set,get方法 public class Employee { private String employeeName; privat

  • 一文教你搞定Java Optional类判空操作

    目录 概述 创建Optional实例 获取Optional中的值 判断Optional是否为空 Optional中的过滤.转换方法 概述 最近项目组内做code review,充斥着大量的.原始的.丑陋的判空语句,大致类似下面的代码: if (user != null) { Address address = user.getAddress(); if (address != null) { Country country = address.getCountry(); if (country

  • Java实现Excel导入导出操作详解

    目录 前言 1. 功能测试 1.1 测试准备 1.2 数据导入 1.2.1 导入解析为JSON 1.2.2 导入解析为对象(基础) 1.2.3 导入解析为对象(字段自动映射) 1.2.4 导入解析为对象(获取行号) 1.2.5 导入解析为对象(获取原始数据) 1.2.6 导入解析为对象(获取错误提示) 1.2.7 导入解析为对象(限制字段长度) 1.2.8 导入解析为对象(必填字段验证) 1.2.9 导入解析为对象(数据唯一性验证) 1.3 数据导出 1.3.1 动态导出(基础) 1.3.2 动

  • Java实现截取字符串的操作详解

    目录 使用JDK截断一个字符串 使用 String 的 substring() 方法 使用 String 的 split() 方法 使用 Pattern 类 使用 CharSequence 的 codePoints() 方法 Apache Commons 库 使用 StringUtils的left() 方法 使用 StringUtils 的 truncate() 方法 Guava库 总结 大家好,我是指北君. 在本文中,我们将学习在Java中把一个String截断到所需的字符数的集中方法. 首先

  • Java实现顺序表的操作详解

    目录 一.顺序表是什么 二.自定义异常 空引用异常 下标越界异常 三.顺序表的方法 顺序表的实现 获取顺序表长度 顺序表是否为空 顺序表是否为满 打印顺序表 末尾新增元素 指定位置新增元素 判断是否包含某元素 查找某个元素对应的位置 获取 pos 位置的元素 给 pos 位置的元素赋值 删除第一次出现的关键字key 清空顺序表 四.自定义顺序表 一.顺序表是什么 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储.在数组上完成数据的增删查改. 数组不就是一个现

  • 工作中Java集合的规范使用操作详解

    目录 一.前言 二.规范使用Java集合 一.前言 现代软件行业的高速发展对开发者的综合素质要求越来越高,因为不仅是编程知识点,其它维度的知识点也会影响到软件的最终交付质量.比如:五花八门的错误码会人为地增加排查问题的难度:数据库的表结构和索引设计缺陷带来的系统架构缺陷或性能风险:工程结构混乱导致后续项目维护艰难:没有鉴权的漏洞代码容易被黑客攻击等.依据约束力强弱及故障敏感性,规约依次分为[强制].[推荐].[参考]三大类.在延伸的信息中,“说明”对规约做了适当扩展和解释:“正例”提倡什么样的编

  • Java switch多值匹配操作详解

    这篇文章主要介绍了Java switch多值匹配操作详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 我们都知道 switch 用来走流程分支,大多情况下用来匹配单个值,如下面的例子所示: /** * @author 栈长 */ private static void test(int value) { switch (value) { case 1: System.out.println("1"); break; case 2:

  • Java二叉搜索树遍历操作详解【前序、中序、后序、层次、广度优先遍历】

    本文实例讲述了Java二叉搜索树遍历操作.分享给大家供大家参考,具体如下: 前言:在上一节Java二叉搜索树基础中,我们对树及其相关知识做了了解,对二叉搜索树做了基本的实现,下面我们继续完善我们的二叉搜索树. 对于二叉树,有深度遍历和广度遍历,深度遍历有前序.中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历,如图: 因为树的定义本身就是递归定义,所以对于前序.中序以及后序这三种遍历我们使用递归的方法实现,而对于广度优先遍历需要选择其他数据结构实现,本例中我们使用队列来实现广度优先遍历.

  • Java 对 Properties 文件的操作详解及简单实例

    Java 对 Properties 文件的操作 简介 在 Java 中,我们常用 java.util.Properties.Properties 类来解析 Properties 文件,Properties 格式文件是 Java 常用的配置文件,它用来在文件中存储键-值对,其中键和值用等号分隔,格式如下: name=shawearn Properties 类是 java.util.Hashtable<Object, Object> 的子类,用于键和值之间的映射. 在对 Properties 格式

  • ThinkPHP空模块和空操作详解

    ThinkPHP的空模块和空操作也是很有实用意义的功能,空模块的概念就是当ThinkPHP找不到指定模块的时候,它会尝试去定位空模块(EmptyAction),执行空模块里面的index操作.同理,空操作也是同样的概念,当系统找不到指定模块下的操作方法的时候,就会尝试去定位空操作方法(empty).其实很好理解,就有点类似php虚拟主机里面的自定义404页面,但它比自定义404更加灵活,利用这个机制,我们可以实现错误页面和一些URL的优化,下面分别详细介绍下空模块和空操作的写法. 1.空模块,在

随机推荐