Java8 Optional类初体验
在现在的公司实习已经一个多月了,在每天的做任务改八哥中,要说给我印象最深,用了以后觉得最爽的一个新知识,就非Optional莫属了。(于是上班偷偷摸鱼整理了这篇文章?)
Optional是Java8引入的一个很有趣的特性,用来解决最经常遇到的烦人问题: NullPointerException(空指针异常)。本质上,Optional是一个包装类,支持泛型地将对象保存在Optional类中,并提供许多有意思的方法来调用和处理存储的对象为空时的异常。
什么?如果调用的Option对象为空?放心啦,你不会去手动new一个Optional对象的,Optional是一个final类,唯二的构造方法都是private的,你需要通过Optional.of()等static方法来获取一个新对象,所以并不会收到一个null对象哦。
接下来跟着代码一步步接近Optional,感受其中的奥秘吧。
一. 不使用 Optional 的情况
- 常规的调用逻辑
1 |
|
- 常规的 null 处理
1 |
|
二. Optional 对象的创建
empty(): 尝试访问 emptyOpt 变量的值会导致 NoSuchElementException。
1
2Optional<User> emptyOpt = Optional.empty();
emptyOpt.get();of(): 如果user为空,会抛出NullPointerException。
1
Optional<User> opt = Optional.of(user);
ofNullable(): 如果对象即可能是 null 也可能是非 null,你就应该使用 ofNullable() 方法。
1
Optional<User> opt = Optional.ofNullable(user);
三. Optional 值的访问
get(): 如果opt为空,会抛出NullPointerException。
1
2
3String name = "John";
Optional<String> opt = Optional.ofNullable(name);
assertEquals("John", opt.get());isPresent(): 检查对象是否存在,null 时为 false。
ifPresent(): 只有 user 用户不为 null 的时候才会执行断言。
1
opt.ifPresent( u -> assertEquals(user.getEmail(), u.getEmail()));
四. Optional 空值的处理
orElse(): 如果user为空,返回user2,否则返回user。
1
2
3
4
5User user = null;
User user2 = new User("[email protected]", "1234");
User result = Optional.ofNullable(user).orElse(user2);
assertEquals(user2.getEmail(), result.getEmail());orElseGet(): 如果user为空,执行Supplier(供应者) 函数式接口,并将返回其执行结果。
1
User result = Optional.ofNullable(user).orElseGet( () -> user2);
orElse() 和 orElseGet() 的不同之处
- 当对象为空而返回默认对象时,行为并无差异。
- 当对象非空值时,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象,orElseGet() 方法不创建 User 对象。
orElseThrow(): 在对象为空的时候抛出异常,而不是返回备选的值。
1
2User result = Optional.ofNullable(user)
.orElseThrow( () -> new IllegalArgumentException());
五. Optional 值的转换和过滤
map(): 将值作为参数调用函数,然后将返回的值包装在 Optional 中。
1
2
3
4
5User user = new User("[email protected]", "1234");
String email = Optional.ofNullable(user)
.map(u -> u.getEmail()).orElse("[email protected]");
// 上面map()后是 Optional 对象,所以可以链式调用orElse()。
assertEquals(email, user.getEmail());flatMap(): 过程与map()一致,但直接返回结果,而非包装为 Optional。
类方法返回 Optional 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 类的定义
private class User {
private String position;
public Optional<String> getPosition() {
return Optional.ofNullable(position);
}
//...
}
// 调用示例
public void whenFlatMap_thenOk() {
User user = new User("[email protected]", "1234");
user.setPosition("Developer");
String position = Optional.ofNullable(user)
.flatMap(u -> u.getPosition()).orElse("default");
assertEquals(position, user.getPosition().get());
}filter(): 接受一个 Predicate 参数,true 返回值,false返回空 Optional。
1
2
3
4
5User user = new User("[email protected]", "1234");
Optional<User> result = Optional.ofNullable(user)
.filter(u -> u.getEmail() != null && u.getEmail().contains("@"));
assertTrue(result.isPresent());
六. Optional 类的链式方法演示
嵌套类,getter返回 Optional 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class User {
private Address address;
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
// ...
}
public class Address {
private Country country;
public Optional<Country> getCountry() {
return Optional.ofNullable(country);
}
// ...
}测试方法
1
2
3
4
5
6
7
8
9
10User user = new User("[email protected]", "1234");
// 因为该自定义类返回的值本身就是 Optional 对象,所以用flatMap();
String result = Optional.ofNullable(user)
.flatMap(u -> u.getAddress())
.flatMap(a -> a.getCountry())
.map(c -> c.getIsocode())
.orElse("default");
assertEquals(result, "default");简化测试方法(Lambda)
1
2
3
4
5String result = Optional.ofNullable(user)
.flatMap(User::getAddress)
.flatMap(Address::getCountry)
.map(Country::getIsocode)
.orElse("default")
七. 参考来源
更多信息以及关于Java9对Optional的增强,可以参考: