JDK8新特性系列——优雅的Optional


前言

你是否在为控制台出现NullPointerException而烦恼,是不是还在用一堆if处理空值。JDK8重磅推出让你的空值处理从此没有if,更加优雅,技术总监看了都说好的Optional类。

它的作用不仅仅是在处理空值上面,它同时也会让程序员养成一种更好的习惯,在以前,程序员在调用一个方法的时候,极可能忘了处理返回值为null的情况,如果返回值为空,极大可能会出现空指针异常。

如果你调用一个方法,返回值是Optional,那么程序员马上就会意识到这个方法可能会返回空值,并且Optional类的API也促使程序员去处理空值情况,从另一个角度提高了程序健壮性。

看到这里你应该理解了Optional类存在的意义以及我们平时应该在哪些场景使用Optional类了。


1. 方法介绍

现在我们来学习下Optional类的一些API,根据这些方法的特点可以分为下面几类:

  1. 创建Optional对象
方法描述
Optional.of(T value)创建一个包含给定非 null 值的 Optional
Optional.ofNullable(T value)创建一个值可能为 null 的 Optional
Optional.empty()创建一个没有值的 Optional
  1. 查询方法
方法描述
isPresent()如果值存在返回 true,否则返回 false
isEmpty()如果值不存在返回 true,否则返回 false(Java 11新增)
  1. 获取值
方法描述
get()如果值存在,返回该值,否则抛出 NoSuchElementException
orElse(T other)如果值存在,返回该值,否则返回 other
orElseGet(Supplier<? extends T> other)如果值存在,返回该值,否则调用 Supplier 获取默认值
orElseThrow(Supplier<? extends X> exceptionSupplier)如果值存在,返回该值,否则调用 Supplier 获取异常并抛出
  1. 转换和链式操作
方法描述
map(Function<? super T,? extends U> mapper)如果值存在,使用给定的映射函数处理并返回一个新的 Optional
flatMap(Function<? super T,Optional<U>> mapper)map 类似,但映射函数的结果直接是一个 Optional
filter(Predicate<? super T> predicate)如果值存在并满足给定的谓词,则返回描述该值的 Optional,否则返回一个空的 Optional
  1. 其他方法
方法描述
ifPresent(Consumer<? super T> action)如果值存在,则使用该值调用指定的消费者
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)如果值存在,使用该值调用指定的消费者,否则执行给定的 Runnable(Java 9新增)

2. 示例代码

在编写一些简单示例之前,我们来回顾一下之前一个示例的部分代码:

Optional<Student> maxScoreStu = stuList.stream()  // 获取Stream流
                .max(Comparator.comparingInt(Student::getScore));  // 直接使用终止操作 max得到结果
maxScoreStu.ifPresent(System.out::println);  // Optional为控制处理提供了更优雅的方式

我们使用终止操作max来获取班级中成绩最高的学生的信息,它返回的是Optional<Student>类型的数据,我们调用ifPresent方法,传入符合Consumer函数式接口的Lambda表达式来消费Student对象。

接下来我们写几个简单的示例,来体验一下Optional类的具体使用:

2.1 示例一

我们现在向封装一个工具函数,用来把字符串转换为数字,我们使用Optional来处理转换异常的情况

    /**
     * 自定义把字符串转换为数字的方法
     * @param str 字符串
     */
    public static Optional<Integer> parseStringToInt(String str){
        try {
            return Optional.of(Integer.parseInt(str));
        }catch (NumberFormatException e){
            return Optional.empty();
        }
    }

    /**
     * 简单的场景,使用Optional来处理一些异常情况
     * 弱化异常处理,强化业务逻辑
     */
    @Test
    public void demo1(){
        Scanner in = new Scanner(System.in);
        Optional<Integer> numOpt;
        do {
            System.out.print("请输入整数:");
            numOpt = parseStringToInt(in.next());
        }while(!numOpt.isPresent());
        // 获取用户输入的数字
        System.out.println("你输入的整数是:"+numOpt.get());
    }

我们的工具方法中,转换成功会返回包含期望值的Optional类,如果转换失败,会在异常处理中返回空的Optional类,这样在调用这个方法的时候不关心异常处理,只关心有没有转换成功,通过Optional提供的方法我们可以很轻松的处理这些逻辑。

所有可能返回空值的方法,我们都可以采用Optional类作为返回类型,能在一定程度上提高程序的健壮性。


2.1 示例二

我们在平时开发中肯定会遇到很多返回值不是Optional的函数,但是返回值又可能是空值,所以我们还有另一种通用的用法来使用Optional来处理空值。

假设我们有一个业务方法返回一个Integer

    /**
     * 模拟的业务方法,获取一个整数
     *
     * @param arg 参数
     */
    public static Integer getSomething(int arg) {
        return arg % 2 == 0 ? null : 1;
    }

我们在调用它的时候需要考虑到它的返回值为空的情况,假设为空的时候我们需要给它赋一个默认值,那么我们可以这样写代码

    @Test
    public void demo2() {
        // 调用业务方法拿到返回值
        Integer res = getSomething(2);
        // 使用Optional来实现空值判断
        Integer result = Optional.ofNullable(res)
                .filter(item -> item > 0)
                .orElse(1);
        System.out.println("结果是:" + result);
    }

使用OptionalofNullable方法来用一个可能为空的值创建一个Optional对象,然后调用filter方法来判断值是否大于0,这个是我们假定的业务逻辑,假设业务中有这个需求,然后我们就要去获取这个值。如果是空的,那么会返回我们填入的1。


总结

Optional这个类让我们从重复又枯燥的空值判断中解脱出来,用另一种更为优雅和符合逻辑的方式来处理Java开发中可能遇到的空值情况。Optional本身API的风格也让代码阅读起来更容易理解,提高代码健壮性的同时也提高了代码的可读性。
轻松使用Optional类的前提是学会函数式接口和Lambda表达式,所以大家掌握这两个东西了吗,如果没有掌握记得看我之前的文章,我们下篇文章见!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值