Java8新特性之:Optional

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8新特性之:Optional相关的知识,希望对你有一定的参考价值。

一. 用Optional取代null

    1. Optional类

        java.util.Optional<T>是一个封装Optional值的类。

        变量存在时,Optional类只是对类进行简单的封装。变量不存在时,缺失的值会被建模成一个“空”的Optional对象,由方法Optional.empty()返回。

        Optional.empty()方法是一个静态工厂方法,它返回Optional类的特定单一实例。

        使用Optional而不是null的一个非常重要而又实际的语义区别:

              声明变量时使用Optional<T>而不是具体的Object,这句声明非常清楚地表明了这里发生变量的缺失是允许的。

    2. 应用Optional的几种模式

        创建Optional对象

          -- 声明一个空的Optional

               Optional<Car> optCar = Optional.empty();

          -- 依据一个非空值创建Optional

               Optional<Car> optCar = Optional.of(car); //如果car是一个null,这段代码会立即抛出NullPointException,而不是等到试图访问car的属性值时才返回一个错误。

          -- 可接受null的Optional(实现序列化的域模型时使用)

              Optional<Car> optCar = Optional.ofNullable(car); //创建一个允许null值的Optional对象,如果car是null,那么得到的Optional对象就是个空对象

        使用map从Optional对象中提取和转换值

public class Person {     //有人有车,有人没车
    private Optional<Car> car;
    public Optional<Car> getCar() { return car;}
}
public class Car {     //有的车有保险,有的车没有保险
    private Optional<Insurance> insurance;
    public Optional<Insurance> getInsurance() { return insurance;}
}
public class Insurance {    //保险公司一定有名字,如果有保险公司没有名字则是出错情况
    private String name;
    public String getName() { return name;}
}
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName)

        使用flatMap链接Optional对象

            使用流时,flatMap方法接受一个函数作为参数,这个函数的返回值时另一个流。这个方法会应用到流中的每一个函数,最终形成一个新的流的流。但是flatMap会用流的内容替换每个新生成的流。即,由方法生成的各个流会被合并或扁平化为一个单一的流。

 Optional<Person> optPerson = Optional.of(person);
          Optional<String> name =  
                                                    optPerson.map(Person::getCar)
                                                                     .map(Car::getInsurance)  //错误代码
                                                                     .map(Insurance::getName)

            getCar返回的是Optional<Car>类型的对象,所以第一个map得到的结果是Optional<Optional<Car>>类型的对象。因此他对getInsurance 的调用是非法的。不支持getInsurance方法。

            使用flatMap会捋平两层结构的Optional为一个包含了Car的单层结构。

      Optional<String> name =  
                                                    optPerson.flatMap(Person::getCar)
                                                                     .flatMap(Car::getInsurance)
                                                                     .map(Insurance::getName)
                                                                     .orElse(""Unknown); //如果Optional结果为空,设置默认值

        默认行为及解引用Optional对象

            -- get()是这些方法中最简单最不安全的方法。如果存在变量,他直接返回封装的变量值,否则抛出NoSuchElementException;

            -- orElse(T other)允许你在Optional对象不包含值时提供一个默认值;

            -- orElseGet(Supplier<? extends T> other)是orElse方法的延迟调用版,Supplier方法只有在Optional对象不含值时才执行调用。如果创建默认值是耗时费力的工作,应该采取这种方式,或你需要非常确定某个方法仅在Optional为空时才调用,也可以考虑该方法(这种情况有严格的限制条件);

            -- orElseThrow(Supplier<? extends X> exceptionalSupplier)和get方法非常类似,当Optional对象为空时都会抛出异常,但使用orElseThrow你可以定制希望抛出的异常;

            -- ifPresent(Consumer<? super T>)让你能在变量值存在时执行一个作为参数传入的方法,否则就不进行任何操作。

        两个Optional对象组合

public Optional<Insurance> nullSafeFindCheapestInsurance(Optional<Person> person, Optional<Car> car) {
    return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c)));
}

        使用filter剔除特定的值

//找出年龄大于或等于minAge参数的Person所对应的保险公司列表
public String getCarInsuranceName(Optional<Person> person, int minAge) {
    return person.filter(p -> p.getAge() >= minAge)
        .flatMap(Person::getCar)
        .flatMap(Car::getInsurance)
        .map(Insurance::getName)
        .orElse("Unknown");
}

            Optional和Stream接口有很多类似的方法。

            Optional类的方法

方法

描述

empty

返回一个空的Optional实例

filter

如果值存在并且满足提供的谓词,就返回包含该值的Optional对象;否则返回一个空的Optional对象

flatMap

如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象

get

如果值存在,就将被Optional封装的值返回,否则抛出一个NoSunchElementException异常

ifPresent

如果值存在,就执行使用该值的方法调用,否则什么也不做

isPresent

如果值存在就返回true,否则返回false

map

如果值存在,就对该值执行提供提供的mapping函数调用

of

将指定值用Optional封装之后返回,如果该值为null,则抛出一个NullPointException异常

ofNullable

将指定值用Optional封装之后返回,如果该值为null,则返回一个空的Optional对象

orElse

如果有值则将其返回,否则返回一个默认值

orElseGet

如果有值则将其返回,否则返回一个由指定的Supplier接口生成的值

OrElseThrow

如果有值则将其返回,否则抛出一个指定的Supplier接口生成的异常



以上是关于Java8新特性之:Optional的主要内容,如果未能解决你的问题,请参考以下文章

Java8新特性之:Optional

Java8新特性:Optional类(超详解)

Java8新特性代码示例(附注释)- 方法引用,Optional, Stream

java8新特性

Java8新特性-官方库新特性

Java8新特性Optional类在处理空值判断场景的应用 回避空指针异常 编写健壮的应用程序