Java8 Optional
核心目的:避免NullPointer异常,避免因为null值引起过多的业务无关的安全检查
可以将Optional看成最多包含一个元素的Stream对象**
通用编程规范中,建议8.6.2:
Java 8使用Optional代替null作为返回值或者可能的缺失值;禁止对optional对象赋值为null
赋值为null从根本上未被了optional设计出来的本意。
参考资料:《Effective Java》55条、《Java8实战》第十章。
API
API List
Optional也提供了类似的基础类型——OptionalInt、 OptionalLong以及OptionalDouble。不推荐使用基础类型的Optional,因为基础类型的Optional不支持map、flatMap以及filter方法。
创建Optional对象
// Eg:
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; }
}
// 1.创建Optional对象
// 空
Optional<Car> optCar = Optional.empty();
// 保证car非null。如果car是一个null,这段代码会立即抛出一个NullPointerException。
Optional<Car> optCar = Optional.of(car);
// 创建一个允许为null值的Optional对象。如果car是null,那么得到的Optional对象就是个空对象。
Optional<Car> optCar = Optional.ofNullable(car);
Optional转化:map与flatMap
// 2.Optional转化
// 从Optional对象中提取和转化值,Optional<T> -> Optional<E>
// map接收非Optional对象,将其转化为Optional对象
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName).orElse("Unknown");
// 多重转换用flatMap
public String getCarInsuranceName(Optional<Person> person) {
return person.flatMap(Person::getCar)
// Optional<Optional<Insurance>>对象,map接收的是非Optional对象
// flatMap接收Optional<T>,转为Optional<E>
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
filter,常用于结合Stream使用
// 3.filter方法,常用于结合Stream使用
// filter方法接受一个谓词作为参数。 如果Optional对象的值存在,并且它符合谓词的条件,
// filter方法就返回其值;否则它就返回一个空的Optional对象。
Optional<Insurance> optInsurance = ...;
optInsurance.filter(insurance ->
"CambridgeInsurance".equals(insurance.getName()))
.ifPresent(x -> System.out.println("ok"));
isPresent与ifPresent
// 4. isPresent与ifPresent
// isPresent与ifPresent,判断是否有值
Optional<String> opt = Optional.of("Baeldung");
assertTrue(opt.isPresent());
opt.ifPresent(name -> System.out.println(name.length()));
缺省:orElse、orElseGet、orElseThrow、get
// 5.缺省:orElse、orElseGet、orElseThrow、get
// orElse。检索Optional对象中的值,如果对象中存在一个值,则返回存在的值,否则返回orElse中的值
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("john");
assertEquals("john", name);
// orElseGet。与orElsel类似,但是这个函数不接收一个“默认参数”,而是一个函数接口
// 区别:orElse相比于orElseGet,多创建了一个对象,即无论是否存在一定会执行orElse。
String nullName = null;
String name = Optional.ofNullable(nullName).orElseGet(() -> "john");
assertEquals("john", name);
// orElseThrow。不存在则抛出异常
String nullName = null;
String name = Optional.ofNullable(nullName).orElseThrow(
IllegalArgumentException::new);
// get。使用get() API 也可以返回被包裹着的值。当值不存在时,抛出NoSuchElementException异常
@Test(expected = NoSuchElementException.class)
public void givenOptionalWithNull_whenGetThrowsException_thenCorrect() {
Optional<String> opt = Optional.ofNullable(null);
String name = opt.get();
}
flatMap解释
传递给流的flatMap方法会将每个正方形转换为另一个流中的两个三角形。那么, map操作的结果就包含有三个新的流,每一个流包含两个三角形,但flatMap方法会将这种两层的流合并为一个包含六个三角形的单一流。
对序列化的支持说明
Optional类设计时没特别考虑将其作为类的字段使用,所以它也并未实现Serializable接口。由于这个原因,如果你的应用使用了某些要求序列化的库或者框架,在域模型中使用Optional,有可能引发应用程序故障。如果一定要实现序列化的域模型,作为替代方案,建议提供一个能访问声明为Optional、变量值可能缺失的接口。