简述一下对Java8中Optional函数编程的认识-如何优雅的解决NPE异常,优雅在何处

为什么会有这篇文章

JDK 8发布后,为java语言添加了很对新的特性,其中一个就是Optional,网上有很多文章介绍如何使用Optional优雅的解决NPE问题,但是“优雅”在哪呢?本篇文章就是介绍“优雅”在何处。

Optional用法

网络上有很多单独讲如何使用Optional的文章,我就不赘述了,可以找一下。
而且在下文中全片贯通如何使用,请继续阅读。

Optional“优雅”的核心

Optional优雅解决NPE问题的核心就是只关注最终使用的对象或属性。何为“最终的对象或属性”?Optional的一个使用场景就是连续的属性调用,如下代码:

people.getCar().getCenterConsole().getState();

这种连续的对象属性调用是最容易出现NPE问题的地方。而最后的**getState()**就是“最终的对象或属性”。
我们最终使用的就是state这个属性,所以不能因为前面的car或者centerConsole对象为null造成我们最终关心的对象state出现问题而无法使用。

具体讲解

使用orElse()方法解决NPE问题

public class OptionalTest {
    public static void main(String[] args) {
        People people = new People();
        Car car = new Car();
        CenterConsole centerConsole = new CenterConsole();
        people.setCar(car);
        car.setCenterConsole(centerConsole);
        centerConsole.setState("关闭");
        
        String centerState = Optional.ofNullable(people)
        	.map(s->s.getCar())
        	.map(s->s.getCenterConsole())
        	.map(s->s.getState())
        	.orElse("unknow");
        	
        System.out.println(centerState);
    }
}

orElse()的作用就是当发生NPE是,返回指定的默认值,此处就是“unknow"。
在orElse()之前有三个map()方法,对应的就是如下代码片段:

people.getCar().getCenterConsole().getState();

在三个map()方法中即级联调用getter()方法的过程中,有任何一处返回了null的话,最终均返回orElse()指定的默认值。这就是其核心“只关注最终使用的对象或属性”。所以后面使用这个“最终的对象或属性”的时候,还是要判断是否为默认值,如果是指定的默认值说明之前某个地方存在问题,需要单独处理。

使用ifPresent()方法解决NPE问题

public class OptionalTest {
    public static void main(String[] args) {
        People people = new People();
        Car car = new Car();
        CenterConsole centerConsole = new CenterConsole();
        people.setCar(car);
        car.setCenterConsole(centerConsole);
        centerConsole.setState("关闭");

        Optional.ofNullable(people)
        	.map(s->s.getCar())
        	.map(s->s.getCenterConsole())
        	.ifPresent(s->s.setState("开启"));
        System.out.println(centerConsole.getState());
    }
}

这里只有两个map()方法的原因是java中对对象类型和基本数据类型的传递方式不同。
以上代码在car或者centerConsole为null时返回“关闭”,如果均不为空则返回“开启”。

关于性能

public class OptionalTest {

    public static void main(String[] args) {
        int total = 10000;//循环次数
        People people = new People();
        Car car = new Car();
        CenterConsole centerConsole = new CenterConsole();
        people.setCar(car);
        car.setCenterConsole(centerConsole);
        centerConsole.setState("关闭");

        long startTime = System.currentTimeMillis();
        for (int i = 0;i<total;i++) {
            Optional.ofNullable(people).map(s -> s.getCar()).map(s -> s.getCenterConsole()).map(s->s.getState()).orElse("unknow");
        }
        long endTime = System.currentTimeMillis();
        long startTime2 = System.currentTimeMillis();
        for (int i = 0;i<total;i++) {
            if (null != people){
                Car car1 = people.getCar();
                if (null != car1){
                    CenterConsole centerConsole1 = car1.getCenterConsole();
                    if (null != centerConsole1){
                        centerConsole.setState("开启");
                    }
                }
            }
        }
        long endTime2 = System.currentTimeMillis();
        System.out.println((endTime-startTime)+" "+(endTime2-startTime2));
        System.out.println(centerConsole.getState());
    }
}

如上测试代码:

  1. 当总循环次数<10000时,使用Optional与普通的嵌套null非空检测查询稳定在30ms;
  2. 当总循环次数>10000&<10000000时,Optional比普通嵌套null非空检测查询性能查询10-20倍,Optional消耗时间稳定在35-65ms之间;
  3. 当总循环次数>10000000时,性能差距呈指数上升。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值