1. 问题和需求
先来看一个简单的类:
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
当我们调用getName
来获取name时,可能值为空,那么就会出现下面这样的代码:
Person p = getPerson();
if(p.getName() != null){
//do something...
}
//或者
if(Person.isNameNotEmpty(p)){
//do something...
}
这里会有两个问题:
- 代码稍微多了且不紧凑;
- 只看方法签名无法直接判断是否为空,无法表示 String|null 这样的类型;
而我们的需求是:
- 优雅地处理空判断;
- 在方法签名上就能看出这个方法的返回值可能存在可能不存在。
2. Optional类介绍
java.util.Optional
类是 Java 8 引入的工具类,表示“可选的”意思,作为单一对象的包装容器,提供一系列方法来优雅的处理空判断和后续操作。
首先是创建Optional对象:
Optional<T> opt = Optional.empty(); //空 Optional
Optional<T> opt1 = Optional.of(value); //不为空的 Optional,如果 value 为 null,会抛出异常
Optional<T> opt2 = Optional.ofNullable(value); //可能为空也可能不为空的 Optional
判断是否为空:
opt.isEmpty();
opt.isPresent();
判空并执行相应动作:
opt.ifPresent(s -> { //if...
//存在的情况,do something...
});
opt.ifPresentOrElse(s -> { //if...else...
//存在的情况,do something...
}, () -> {
//不存在的情况,do something...
});
从Optional中取值:
opt.get(); //取出值或抛出异常
opt.orElse(defValue); //取出值或者为默认值
opt.orElseGet(() -> getDefXXXValue()); //取出值或者获取默认值
opt.orElseThrow(); //取出值或抛出异常,同 get
opt.orElseThrow(() -> new IllegalStateException("xxx"));//取出值或抛出指定
链式调用:
int value = opt
.filter(s -> s.length() > 0) //过滤长度为 0 的字符串
.or(() -> Optional.of("empty")) //如果为空就换成"empty"
.map(s -> "str:" + s) //添加前缀
.flatMap(s -> { //转成整数
try{
return Optional.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return Optional.empty();
}
})
.orElse(0); //获取值或默认值
转成流对象:
Stream<T> stream = opt.stream();
//然后就可以用Stream的API来处理Optional里的值了。
最后,我们可以用Optional来修改最上面的例子:
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//关心是否为空的就可以用这个方法来放心优雅使用了
public Optional<String> optName() {
return Optional.ofNullable(name);
}
}