Optional 类解决空指针异常
前言
空指针异常是导致 Java 应用程序失败的最常见原因。以前,为了解决空指针异常,Google 公司著名的 Guava 项目引入了 Optional 类,Guava 通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到 Google Guava 的启发,Optional 类已经成为 Java8 类库的一部分。Optional 实际上是个容器:它可以保存类型 T 的值,或者仅仅保存 null。Optional 提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 范例
构造方式
Optional 的三种构造方式:Optional.of(obj),Optional.ofNullable(obj) 和 Optional.empty()。
Optional.of(),依据一个非空值创建 Optional
// 如果 car 是一个 null, 这段代码会立即抛出
// NullPointException, 而不是等到试图访问 car 的属性值时才返回一个错误.
Optional<Integer> optCar = Optional.of(car);
Optional.ofNullable(),可接受 null 的 Optional(实现序列化的域模型时使用)
// 创建一个允许 null 值的 Optional 对象,
// 如果 car 是 null, 那么得到的 Optional 对象就是个空对象.
Optional<Integer> optCar = Optional.ofNullable(car);
Optional.empty(),所有 null 包装成的 Optional 对象。
// 声明一个空的 Optional
Optional<Integer> empty = Optional.empty();
isPresent()/ifPresent(Consumer consumer)
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);
ifPresent(Consumer consumer):如果 option 对象保存的值不是 null,则调用 consumer 对象,否则不调用。
// 如果不是 null, 调用 Consumer; 如果 null, 不调用 Consumer
optional1.ifPresent(new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println("value is" + t);
}
});
// Lambda 表达式写法
optional1.ifPresent(t -> System.out.println("value is" + t));
orElse(value)/orElseGet(Supplier supplier)
orElse(value):如果 optional 对象保存的值不是 null,则返回原来的值,否则返回 value。
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
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()
orElseThrow():值不存在则抛出异常,存在则什么不做,有点类似 Guava 的 Precoditions。
Optional<Integer> optional = Optional.ofNullable(null);
optional.orElseThrow(() -> {
throw new NullPointerException();
});
filter(Predicate)
filter(Predicate):判断 Optional 对象中保存的值是否满足 Predicate,并返回新的 Optional。
Optional<Integer> optional = Optional.ofNullable(1);
Optional<Integer> filter = optional.filter((a) -> a == 1);
map(Function)/flatMap(Function)
map(Function) 如果有值,则对其执行调用 mapping 函数得到返回值,否则返回空 Optional。如果返回值不为 null,则创建包含 mapping 返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。
Optional<String> upperName = name.map((value) -> value.toUpperCase());
System.out.println(upperName.orElse("No value found"));
flatMap(Function) 如果有值,为其执行 mapping 函数返回 Optional 类型返回值,否则返回空 Optional。flatMap 与 map(Funtion)方法类似,区别在于 flatMap 中的 mapper 返回值必须是 Optional。调用结束时,flatMap 不会对结果用 Optional 封装。[P.S. 参考博文 [3]:Cascading Optional Objects Using the flatMap Method]
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));
Optional 类的链式方法
错误示范 / 正确示范
示范(一)
// ** 错误示范
Optional<User> user = ......
if (user.isPresent()) {
return user.getOrders();
} else {
return Collections.emptyList();
}
// 二者实质上是没有任何分别
User user = .....
if (user != null) {
return user.getOrders();
} else {
return Collections.emptyList();
}
// ** 正确示范
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())
// map 是可能无限级联的, 比如再深一层, 获得用户名的大写形式
return user.map(u -> u.getUsername())
.map(name -> name.toUpperCase())
.orElse(null);
示范(二)
// ** 错误示范
String version = "UNKNOWN";
if(computer != null){
Soundcard soundcard = computer.getSoundcard();
if(soundcard != null){
USB usb = soundcard.getUSB();
if(usb != null){
version = usb.getVersion();
}
}
}
// ** 正确示范
String version = computer.map(Computer::getSoundcard)
.map(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
参考博文
[1]. Java 8 Optional 类深度解析
[2]. 使用 Java8 Optional 的正确姿势
[3]. Tired of Null Pointer Exceptions? Consider Using Java SE 8’s Optional!
source:https://morning-pro.github.io/archives/8eb6feba.html
喜欢,在看