← 返回首页
JavaSE基础教程(九十四)
发表时间:2020-10-30 00:50:14
Optional

空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

例如:

// 参数不能是null
Optional<Integer> optional1 = Optional.of(1);
// 参数可以是null
Optional<Integer> optional2 = Optional.ofNullable(null);
// 参数可以是非null
Optional<Integer> optional3 = Optional.ofNullable(2);

isPresent():判断值是否存在

Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

// isPresent判断值是否存在
System.out.println(optional1.isPresent() == true);
System.out.println(optional2.isPresent() == false);

orElse(value):如果optional对象保存的值不是null,则返回原来的值,否则返回value

Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

// orElse
System.out.println(optional1.orElse(1000) == 1);// true
System.out.println(optional2.orElse(1000) == 1000);// true

orElseGet(Supplier supplier):功能与orElse一样,只不过orElseGet参数是一个对象

Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

System.out.println(optional1.orElseGet(() -> {
    return 1000;
}) == 1);//true

System.out.println(optional2.orElseGet(() -> {
    return 1000;
}) == 1000);//true

orElseThrow():值不存在则抛出异常,存在则什么不做,有点类似Guava的Precoditions

Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

optional1.orElseThrow(()->{throw new IllegalStateException();});

try
{
     // 抛出异常
     optional2.orElseThrow(()->{throw new IllegalStateException();});
}
catch(IllegalStateException e )
{
    e.printStackTrace();
}

map(Function):对Optional中保存的值进行函数运算,并返回新的Optional(可以是任何类型)

Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

Optional<String> str1Optional = optional1.map((a) -> "key" + a);
Optional<String> str2Optional = optional2.map((a) -> "key" + a);

System.out.println(str1Optional.get());// key1
System.out.println(str2Optional.isPresent());// false

Optional最大的好处是简化if-else和更优雅的去除多层if嵌套。

实例: 定义Person类,一个人持有一个汽车的引用。

class Car{
    private String brand;
    private String color;

    public Car() {
    }

    public Car(String brand, String color) {
        this.brand = brand;
        this.color = color;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

class Person {

    private String name;
    private String gender;
    private int age;
    private Car car;

    public Person() {
    }

    public Person(String name, String gender, int age,Car car) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.car = car;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public String introduce(){
        return "hello,my name is:" + this.name + ",I am " + this.age + " years old!";
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }
}

在OptionalDemo中定义有sayHello方法,判断person对象如果不为空则获得其自我介绍的字符串,并打印,否则输出"unknown".传统的java代码实现方式如下:

public class OptionalDemo{
   public static void sayHello(Person p){
        if(p!=null){
            System.out.println(p.introduce());
        }else{
            System.out.println("unknown");
        }
    }
}

主方法测试,运行结果如下:

public static void main(String[] args) throws Exception {
       Person p = new Person("张三","男",30,new Car("BMW","red"));
        sayHello(p);
}

运行结果如下:

如果给sayHello方法传入null对象,运行结果如下:

public static void main(String[] args) throws Exception {
       Person p = null;
       sayHello(p);
}

上面的sayHello方法,使用Optional可以大大精简if-else.实现如下:

public static void sayHello(Person p){
        Optional<Person> person = Optional.ofNullable(p);
        //写法一: 
        //System.out.println(person.map(per -> per.introduce()).orElse("unknown"));
        //写法二:
        System.out.println(person.map(Person::introduce).orElse("unknown"));
    }

实现效果与传统if-else完全相同。

再例如:在getCarBrand方法中获取这个人持有的汽车品牌。传统实现方式如下:

public static String getCarBrand(Person p) throws Exception{
       if(p!=null){
             Car car = p.getCar();
             if(car!=null){
                 return car.getBrand();
             }
       }
      throw new Exception("Person or Car is null!");
 }

在主方法中测试,传入一个汽车属性为null的Person对象。

public static void main(String[] args) throws Exception {
        Person p = new Person("张三","男",30,null);
        System.out.println(getCarBrand(p));

}

运行结果如下:

使用Optional可以优雅的去除多重if-else语句,实现代码如下:

public static String getCarBrand(Person p) throws Exception{
        Optional<Person> person = Optional.ofNullable(p);
        return person.map(Person::getCar).map(Car::getBrand).orElseThrow(()->new Exception("Person or Car is null!"));
        //或者下面的写法
        //return person.map(per->per.getCar()).map(c->c.getBrand()).orElseThrow(()->new Exception("Person or Car is null!"));
}

实现效果与传统多重if-else完全相同。