如何理解Java8中的Optional能消除空指针

Optional的作用是什么?
主要作用是消除空指针,但其本质就通过Optional来区分代码中那些内容是可以为空的,那些不可以为空。
我们平时的代码通过 xxx != null来判断某个对象不为空,所以我们常见的代码是这样的:

if(xxx !=null) {
xxx.get();
}

获取某个对象内部的值,需要先判断是否为空,如果没有判断就进行调用,那么很可能发生空指针NullPointerException。
而如果某个对象是可以为空的,那么使用Optional封装后,我们的代码就会比较流畅的编写,而不需要写过多的if判断,然后再获取其值。
比如人的名字肯定是不为空的,而人的汽车则是有的人有,有的人没有。
人和车这样定义:

@Data
public class OptPerson {

    private String name;

    private Optional<OptCar> optCar;
	
}


import lombok.Data;

@Data
public class OptCar {

    private String carName;

    private OptCarBrand optCarBrand;
}

import lombok.Data;

@Data
public class OptCarBrand {

    private String brandName;
}


我们来看demo:
import java.util.Optional;

/**
 * @author itzhimei
 */
public class OptionalEmpty {

    public static void main(String[] args) {
        //test1();
        test2();
        //test3();
    }

    public static void test1() {
        OptPerson optPerson = new OptPerson();
        optPerson.setName("IT之美");
        optPerson.setOptCar(Optional.empty());

        System.out.println(optPerson);
        System.out.println(optPerson.getOptCar().get().getOptCarBrand());

    }
    /* 输出
    OptPerson(name=IT之美, optCar=Optional.empty)
    Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at com.itzhimei.base.lambda.optional.OptionalEmpty.test1(OptionalEmpty.java:20)
	at com.itzhimei.base.lambda.optional.OptionalEmpty.main(OptionalEmpty.java:11)
     */

    public static void test2() {
        OptPerson optPerson = new OptPerson();
        optPerson.setName("IT之美");
        optPerson.setOptCar(Optional.empty());

        System.out.println(optPerson);
        System.out.println("car为空:" + optPerson.getOptCar().orElse(new OptCar()).getOptCarBrand());
    }
    /* 输出
    OptPerson(name=IT之美, optCar=Optional.empty)
    car为空:null
     */

    public static void test3() {
        OptPerson optPerson = new OptPerson();
        optPerson.setName("IT之美");
        //optPerson.setOptCar(Optional.empty());

        System.out.println(optPerson);
        System.out.println(optPerson.getOptCar().get().getOptCarBrand());

        System.out.println("car为空:" + optPerson.getOptCar().orElse(new OptCar()).getOptCarBrand());
    }
    /* 输出
    OptPerson(name=IT之美, optCar=null)
    Exception in thread "main" java.lang.NullPointerException
	at com.itzhimei.base.lambda.optional.OptionalEmpty.test1(OptionalEmpty.java:20)
	at com.itzhimei.base.lambda.optional.OptionalEmpty.main(OptionalEmpty.java:11)
     */
}

我们先看test1方法,这里面最重要的一行代码就是:optPerson.setOptCar(Optional.empty()),有了这一行代码,执行方法后还是报错,但是并不是空指针,这是因为Optional的get方法使用之前需要先调用isPresent()方法判断对象是否为空。

public static void test1() {
        OptPerson optPerson = new OptPerson();
        optPerson.setName("IT之美");
        optPerson.setOptCar(Optional.empty());

        System.out.println(optPerson);
        System.out.println(optPerson.getOptCar().get().getOptCarBrand());

    }
    /* 输出
    OptPerson(name=IT之美, optCar=Optional.empty)
    Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at com.itzhimei.base.lambda.optional.OptionalEmpty.test1(OptionalEmpty.java:20)
	at com.itzhimei.base.lambda.optional.OptionalEmpty.main(OptionalEmpty.java:11)
     */

我们再看test2方法,test2方法获取汽车用的是optPerson.getOptCar().orElse(new OptCar()).getOptCarBrand(),我们可以看到代码并没有报错,输出的是null。
这里空竟然没有空指针,也没有报错,这就是Optional的强大之处,因为我们已经声明过car可以使empty,optPerson.setOptCar(Optional.empty()),所以在后续使用时,对empty的car调用,也不会产生空指针。
这就是我们在代码设计时,需要我们开发人员区分,哪些是可以为空的,可以为空的可以定义成Optional这样的类型,并在创建对象是将car声明为empty,那么后续调用,就变car是empty的,也不会产生空指针,从而减少了if判空的操作。
这是一种设计上的应用和选择。

我们先看test3方法, test3方法去掉了optPerson.setOptCar(Optional.empty())行代码,执行还是报了空指针,所以如果对象是null,直接调用null.xxx(),那么还是会空指针。