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、变量值可能缺失的接口。

猜你喜欢

转载自blog.csdn.net/weixin_38370441/article/details/112313564