Optional<T> 是什么
Optional<T> 是 Java8 引入的一个容器,用于包装可能为 null 的值,它的主要目的是:
1、显示的表示“值可能不存在”
2、强制调用方处理空值的情况
关键方法
声明一个Optional
of(T value)
包装非 null 值,这是个静态方法。
Optional<String> s = Optional.of("Hello world!");
ofNullable(T value)
包装可能为 null 的值,这也是个静态方法。
Optional<String> s = Optional.ofNullable("Hello world!");
empty()
返回一个包装 null 的Optional
Optional<String> s = Optional.empty();
// 等同于 Optional<String> s = Optional.ofNullable(null);
存在性判断
isPresent()
判断是否有非null元素。
Optional<String> s = someMethod();
if (s.isPresent()) {
// do something
}
isEmpty()
判断是否是 null 元素
Optional<String> s = someMethod();
if (s.isEmpty()) {
// do something
}
条件执行
ifPresent(Consumer)
如果是非null就执行一些操作,是null则什么也不做,只是简单的消费者,不能return值。
Optional<String> s = someMethod();
s.ifPresent(v -> {
System.out.println("current value: " + v);
// do something with the value
});
ifPresentOrElse(Consumer)
可以同时指定null和非null两种场景的回调函数。
Optional<String> s = someMethod();
s.ifPresentOrElse(v -> {
System.out.println("current value: " + v);
// do something with the value
},
() -> {
System.out.println("no value present");
// do something else
});
获取值
get()
直接获取内部的值,如果是null,则会抛出异常。建议先 isPresent() 先检查是否存在值,再调用get()
Optional<String> s = someMethod();
if (s.isPresent()) {
System.out.println(s.get());
}
orElse(T value)
获取内部的值,如果为null,则返回给定的默认值。
Optional<String> s = someMethod();
String s1 = s.orElse("Default value");
orElseGet(Supplier)
和 orElse 最终的效果一样。
Optional<String> s = someMethod();
String s1 = s.orElseGet(() -> someComplexMethod());
和 orElse 的区别在于:
1、orElse是不管optional内部是否为null,都会执行默认方法,适用于默认值为简单常量的场景。
2、orElseGet 会先判断optional 是否为null,当为null才会执行默认方法
所以如果这样调用就不太好,因为一定会执行复杂的方法,耗费性能:
Optional<String> s = someMethod();
// 错误演示
String s1 = s.orElse(someComplexMethod());
orElseThrow(Supplier)
获取值,如果为null,则抛出给定的异常。
Optional<String> s = someMethod();
String s1 = s.orElseThrow(() -> new RuntimeException("Error!"));
过滤和转换
filter(Predicate)
给定一个判断条件,如果满足条件,则什么也不改变;如果不满足条件,则内部元素被拦截,不会往下游走,也就是变成了 Optional.empty()。
Optional<String> s = someMethod();
// 如果 v.length() > 5 条件不成立,则 s1 变成了空集合
Optional<String> s1 = s.filter(v -> v.length() > 5);
map(Function)
这个就好理解了,改变元素的形状或者值。
// 改变形状:从 Optional<Integer> 经过演算变成 Optional<String>
Optional<Integer> s = someMethod();
Optional<String> s1 = s.map(Object::toString);
// 改变内容:元素类型不变,但是值发生改变
Optional<String> s = someMethod();
Optional<String> s1 = s.map(v -> v + "hello");
flatMap(Function)
扁平化转换,处理嵌套的Optional,可以将 Optional<Optional<String>> 转换成 Optional<String>
Optional<String> s = someMethod();
Optional<String> t = s.flatMap(v -> {
// 这里不同,返回的不是元素的类型,而是需要再包裹Optional
return Optional.of(v + " world!");
});
最佳实践
只使用在方法返回值/null检查
Optional 的目的之一是强制调用方处理空值的情况,所以推荐在方法返回值的时候使用,不要在参数或者对象属性中使用。同时也可以进行null检查。
// √ 推荐用法: 方法返回值
public Optional<String> someMethod() {
// do some work
return Optional.empty();
}
// √ 推荐用法: null值检查
public void someMethod() {
String s = somefun(); // 不知道s是不是null
String t = Optional.ofNullable(s)
.orGet("hello"); // 中间可以配合filter和map进行演算
}
不要包装集合类型
Optional 已经是一个集合,没必要在包括另外一个集合类型,意义不是很大,如果是空数据,返回空集合即可。
// 不推荐用法
public Optional<List<String>> someMethod() {
// do some work
List<String> list = new ArrayList<>();
return Optional.ofNullable(list);
}
// 返回集合类型没必要用到 Optional, 当为null直接返回空集合即可
public List<String> someMethod() {
// do some work
List<String> list = new ArrayList<>();
if (list == null) {
return new ArrayList<>();
}
return list;
}
避免 isPresent() + get() 的啰嗦写法
这样容易写出命令式代码,不够优雅,并且Optional的提出就是为了避免繁琐的 if 判断。
// 不推荐写法
Optional<String> s = someMethod();
if (s.isPresent()) {
System.out.println(s.get());
// do something with the value
}
而是推荐以下写法:
1、当只是简单的消费数据,不需要return,推荐使用 ifPresent(Consumer)
Optional<String> s = someMethod();
s.ifPresent(v -> {
System.out.println("current value: " + v);
// do something with the value
});
2、需要 return 值,推荐 map + orElse/orElseGet
// 不推荐写法
public String fun() {
Optional<String> s = someMethod();
if (s.isPresent()) {
System.out.println(s.get());
// do something with the value
return "anyhow" + s.get();
}
return "other";
}
// 推荐写法, 使用 map + orElse/orElseGet
public String fun() {
Optional<String> s = someMethod();
return s..map(value -> {
System.out.println(value);
return "anyhow" + value;
})
.orElse("default"); // 这里可以替换成 orElseGet
}