对于NPE,Java8对于null判定提供了一种更加优雅的实现,Optional类。
比如我们要返回一个字符串的长度
java8以前:
if(null == str) {
return 0;
}
return str.length();
使用Optional
return Optional.ofNullable(str).map(String::length).orElse(0);
Optional的代码相对更加简洁,当代码量较大时,我们很容易忘记进行null判定,但是使用Optional类可以很大的避免这类问题
一、基本使用
1.1 Optional对象的创建
- 创建空对象
Optional<String> optStr = Optional.empty();
- 创建对象(不允许为空)
Optional<String> optStr = Optional.of(str); // 当str为null的时候,将抛出NullPointException
- 创建对象(允许为空)
Optional<String> optStr = Optional.ofNullable(str); // 如果str是null,则创建一个空对象
1.2 流式数据处理
Optional类提供了两个基本的流式处理:映射和过滤
我们先创建一个User类
public class User {
private long id;
private String name;
private int age;
private Optional<Long> phone;
private Optional<String> email;
public User(String name, int age) {
this.name = name;
this.age = age;
}
// 省略getter和setter
}
这里phone和email我们使用Optional类定义
-
映射:map与flatMap
获取用户名字
User user = new User("jack", 23);
String name = Optional.ofNullable(user).map(User::getName).orElse("no name");
如果user为null或者user.getName()为null,返回no name,
只有user与user的name同时不为null时,结果才是有效的。
获取用户手机时,map之后返回的是Optional,我们把这种称为Optional嵌套,我们必须再map一次才能拿到想要的结果
long phone = Optional.ofNullable(user).map(User::getPhone).map(Optional::get).orElse(-1L);
其实我们有一种更好的方式
phone = Optional.ofNullable(user).flatMap(User::getPhone).orElse(-1L);
<font color="red">这种方式有问题,如果user不为null,但是phone为null时,报NPE</font>
- 过滤:filter
假若我们希望筛选18周岁以上的成年人
Optional.ofNullable(user).filter(u -> u.getAge() >= 18).ifPresent(u -> System.out.println("Adult:" + u));
如果user年龄超过18,则打印user
1.3 默认行为
- get()
get方法用于获取变量的值,当变量不存在时抛NoSuchElementExcepton
- orElse(T other)
当Optional的变量不满足给定条件时,执行orElse
- orElseGet(Supplier<? extends X> expectionSupplier)
如果条件不成立时需要执行相对复杂的逻辑而不是简单的返回操作,则可以使用orElseGet实现
String name = Optional.ofNullable(user).map(User::getName).orElseGet(() -> {
System.out.println("这个用户没有名字吗?");
return "no name";
});
当user==null或者user.getName() == null时,会运行orElseGet参数的方法。
- orElseThrow(Supplier<? extends X> expectionSupplier)
name = Optional.ofNullable(user).map(User::getName).orElseThrow(Exception::new);
或者
name = Optional.ofNullable(user).map(User::getName).orElseThrow(() -> {
System.out.println("这个用户没有名字,我抛异常了");
return new Exception();
});
- ifPresent(Consumer<? super T>)
二、注意事项
Optional是一个final类且未实现任何接口(比如Serializable),所以当我们在利用该类包装定义类的属性的时候,如果我们定义的类有序列化的需求,那么因为 Optional 没有实现 Serializable 接口,这个时候执行序列化操作就会有问题:
public class User implements Serializable {
private long id;
private String name;
private int age;
private Optional<Long> phone; // 不能序列化
private Optional<String> email; // 不能序列化
}
不过我们可以采用如下替换策略 Optinal:
private long phone;
public Optional<Long> getPhone() {
return Optional.ofNullable(this.phone);
}
看来 Optional 类在设计的时候就没有考虑将它作为类的字段使用。
网友评论