你是否曾经被 NullPointerException 异常折磨的苦不堪言?你是否曾为复杂的POJO 类写非空判断,为那多个 if xxx != null 或多层嵌套 if xxx != null 的代码感到烦恼心累?
呐,程序猿们,我们是时候用Java 8 的 Optional 类进行优雅的判空啦,当然,如果你用的是 Java 8 的话(:з」∠)。
Optional 是什么?
java.util.Optional 类是 Java 8 引入的一个新的类,是一个容器,可以保存类型为T的值,也可以保存null值,它提供了许多有用的方法,使得我们可以不用显示进行空值检查。
Optional 的类方法
方法 描述
- static Optional empty() 返回一个空的 Optional 实例
- static Optional of(T value) 返回一个包含指定 value 的Optional,如果 value 为空,则抛出 NullPointerException
static Optional ofNullable(T value) 将指定的值用 Optional 封装之后返回,如果 value 为null,则返回一个空的 Optional 对象 - T orElse(T other) 如果 Optional 有值,则将其返回,否则返回指定 other 值
- T orElseGet(Supplier<? extends T> supplier) 如果 Optional 有值则将其返回,否则返回一个由指定的Supplier 接口生成的值
- T orElseThrow() 如果 Optional 有值,则将其返回,否则抛出 NoSuchElementException 异常
- T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X 如果 Optional 有值则将其返回,否则抛出一个由指定的 Supplier 接口生成的异常
上面基本上列出了 Optional 类的所有方法,下面挑几个常用的方法进行介绍:
public class {
@AllArgsConstructor
@NoArgsConstructor
private static class Basket {
private Apple apple;
}
@AllArgsConstructor
@NoArgsConstructor
private static class Apple {
private String color;
private Double weight;
}
public static void main(String[] args) {
Apple apple = new Apple("red", 20.00);
Basket basket = new Basket(apple);
try {
Optional<Apple> optionalApple1 = Optional.of(apple);
} catch (NullPointerException e) {
e.printStackTrace();
}
// 将 apple 用 Optional 封装之后返回,如果 apple 为null,则返回一个空的 Optional 对象
// 推荐采用这种方式
Optional<Apple> optionalApple2 = Optional.ofNullable(apple);
try {
// 如果 optionalApple 包含有值,则返回该值,否则抛出 NoSuchElementException 异常
Apple apple1 = optionalApple2.get();
} catch (NoSuchElementException e) {
e.printStackTrace();
}
// 如果不想get()抛出异常,可以使用 orElse() 方法
// 如果 optionalApple2 有值,则将其返回,否则返回指定 null 值
Apple apple1 = optionalApple2.orElse(null);
// 如果 optionalApple2 有值存在,就对该值执行提供的mapping 函数调用
Optional<Double> weightOptional = optionalApple2.map(Apple::getWeight);
// 可以与 get() 一起使用,或者与 orElse() 一起使用
Double weight1 = optionalApple2.map(Apple::getWeight).get();
Double weight2 = optionalApple2.map(Apple::getWeight).orElse(00.00);
// 从 Basket 中 获取 Apple 的 weight
Double appleWeight1 = Optional.ofNullable(basket)
.map(Basket::getApple)
.map(Apple::getWeight)
.orElse(00.00);
// 使用 orElseThrow
Double appleWeight2 = Optional.ofNullable(basket)
.map(Basket::getApple)
.map(Apple::getWeight)
.orElseThrow(NullPointerException::new);
}
}
使用 Optional 进行优雅判空
还是用上面列举的类,如果不用使用 Optional,想要获取 Basket 类内的 Apple 类的 weight 值,得这样写:
public double getAppleWeight(Basket basket){
if (basket != null){
Apple apple = basket.getApple();
if (apple != null){
Double weight = apple.getWeight();
if (weight != null){
return weight;
}
}
}
return 0.0;
}
看看这个 if 嵌套,emm…,这还是较为简单的 pojo 类,如果是复杂的,简直不堪入目啊。
而在 Optional 的加持下,只需这样写:
public double getAppleWeight(Basket basket){
return Optional.ofNullable(basket)
.map(Basket::getApple)
.map(Apple::getWeight)
.orElse(0.0);
}
瞬间代码就清爽了,嘻嘻,人也跟着欢快起来了。
当然 Optional 不止能进行优雅的判空,还可以利用 Optional 的其它的API,进行一些神奇的操作,比如使用 filter 进行参数校验之类的。