简介
为了避免null导致NullPointerException,JAVA8新增了Optional来避免这种情况的发生。
当变量T存在时, Optional类只是对类简单封装。当变量T不存在时,缺失的值会被建模成一个“空”的Optional对象,由方法Optional.empty()返回。
null引用和Optional.empty()有什么本质的区别吗?从语义上,可以把它们当作一回事儿,但是实际中它们之间的差别非常大:如果尝试引用一个null, 一定会触发NullPointerException,而Optional.empty()则没这个问题,它是Optional类的一个有效对象,多种场景都能正常调用。
但如果你就是不使用Optional,那么可以理解为你是允许该对象为null。
String name;按照JAVA8约定,这种形式的变量是不允许出现null情况的,如果出现null,则只能说是业务流程出现问题。
Optional<String> name;按照JAVA8约定,这种形式的变量是允许出现null情况的。
方法使用案例
Optional<Car> optCar = Optional.empty();声明一个空的Optional Optional<Car> optCar = Optional.of(car);依据一个非空值创建Optional Optional<Car> optCar = Optional.ofNullable(car);可接受null的Optional Optional<Insurance> optInsurance = Optional.ofNullable(insurance); Optional<String> name = optInsurance.map(Insurance::getName);可以把Optional对象看成一种特殊的集合数据,它至多包含一个元素。如果Optional包含一个值,那函数就将该值作为参数传递给map,对该值进行转换。如果Optional为空,就什么也不做。使用 map 来从Optional对象中提取和转换值 person.flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unknown");flatMap方法接受一个函数作为参数,这个函数的返回值是另一个流。这个方法会应用到流中的每一个元素,最终形成一个新的流的流。但是flagMap会用流的内容替换每个新生成的流。换句话说,由方法生成的各个流会被合并或者扁平化为一个单一的流。 optInsurance.filter(insurance->"CambridgeInsurance".equals(insurance.getName())).ifPresent(x->System.out.println("ok"));filter方法接受一个谓词作为参数。 如果Optional对象的值存在,并且它符合谓词的条件,filter方法就返回其值;否则它就返回一个空的Optional对象。如果你还记得我们可以将Optional看成最多包含一个元素的Stream对象,这个方法的行为就非常清晰了。 如果Optional对象为空,它不做任何操作,反之,它就对Optional对象中包含的值施加谓词操作。如果该操作的结果为true,它不做任何改变,直接返回该Optional对象,否则就将该值过滤掉,将Optional的值置空。 |
常用方法API
①get()是这些方法中最简单但又最不安全的方法。如果变量存在,它直接返回封装的变量 值,否则就抛出一个NoSuchElementException异常。所以,除非你非常确定Optional变量一定包含值,否则使用这个方法是个相当糟糕的主意。此外,这种方式即便相对于嵌套式的null检查,也并未体现出多大的改进。 ②orElse(T other)允许在Optional对象不包含值时提供一个默认值。 ③orElseGet(Supplier<? extends T> other)是orElse方法的延迟调用版, Supplier 方法只有在Optional对象不含值时才执行调用。如果创建默认值是件耗时费力的工作, 应考虑采用这种方式,或者需要非常确定某个方法仅在Optional为空时才进行调用,也可以考虑该方式。 ④orElseThrow(Supplier<? extends X> exceptionSupplier)和get方法非常类似,它们遭遇Optional对象为空时都会抛出一个异常,但是使用orElseThrow可以定制希望抛出的异常类型。 ⑤ifPresent(Consumer<? super T>)能在变量值存在时执行一个作为参数传入的方法,否则就不进行任何操作。 |
API列表
1.empty:返回一个空的Optional实例。
2.filter:如果值存在并且满足提供的谓词,就返回包含该值的 Optional对象;否则返回一个空的Optional对象。
3.flatMap:如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象。
4.get:如果该值存在,将该值用Optional封装返回,否则抛出一个NoSuchElementException异常。
5.ifPresent:如果值存在,就执行使用该值的方法调用,否则什么也不做。
6.isPresent:如果值存在就返回true,否则返回false。
7.map:如果值存在,就对该值执行提供的mapping函数调用。
8.of:将指定值用Optional封装之后返回,如果该值为null,则抛出一个NullPointerException异常。
9.ofNullable:将指定值用Optional封装之后返回,如果该值为null,则返回一个空的Optional对象。
10.orElse:如果有值则将其返回,否则返回一个默认值。
11.orElseGet:如果有值则将其返回,否则返回一个由指定的 Supplier接口生成的值。
12.orElseThrow:如果有值则将其返回,否则抛出一个由指定的 Supplier接口生成的异常。
改造老旧代码
Null转Optional:
Optional<Object> value =
Optional.ofNullable(map.get("key"));
处理异常:
try {
return Optional.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return Optional.empty();
}
注意事项
①Optional也提供了类似的基础类型:OptionalInt、 OptionalLong以及OptionalDouble。但是这些基础类型却不支持map、flatMap以及filter方法。
②Optional对象无法由基础类型的Optional组合构成,比如:OptionalInt类型的对象,你就不能将其作为方法引用传递给另一个Optional对象的flatMap方法。
③Optional类并未实现Serializable接口。