前言
Optional 是 Java 8 引进的一个新特性,它是一个容器对象,可以包含或不包含非空值。
Optional
Optional的机制类似于受检异常,强迫API调用者面对没有返回值的现实,因为程序直接返回 null 很可能导致调用端产生错误(空指针异常!)。
Optional 是用来作为方法返回值的,目的是清晰地表达返回值中没有结果的可能性。
常用方法及调用方式
of(value)
:创建一个包含指定非空值的Optional
对象。ofNullable(value)
:创建一个可能为空的Optional
对象。如果传入的值为null
,则返回一个空的Optional
。empty()
:创建一个空的Optional
对象。isPresent()
:检查Optional
对象是否包含值。get()
:获取Optional
对象中的值。在调用之前应先使用isPresent()
进行判断。
Optional
支持方法链式调用,使得我们可以在一系列操作中进行空值检查和转换。
下面是一个简单的示例:
1 | Optional<String> optionalValue = Optional.of("Hello"); |
除了常用方法,还有一些方法可以对Optional
对象进行快捷操作,如上面出现的orElse
,下面介绍其中一些。
orElse(T other)
:如果包含的值存在,则返回该值;如果不存在,则返回默认值other
。无论值是否存在,都会进行计算,并返回结果。示例:
1
2
3
4
5
6
7Optional<String> optionalValue = Optional.of("Hello");
String value = optionalValue.orElse("Default Value");
System.out.println(value); // 输出:Hello
Optional<String> emptyOptional = Optional.empty();
String defaultValue = emptyOptional.orElse("Default Value");
System.out.println(defaultValue); // 输出:Default ValueorElseGet(Supplier<? extends T> other)
:如果包含的值存在,则返回该值;如果不存在,则使用提供的Supplier
函数来计算并返回值。与orElse()
类似,但在值不存在时,Supplier
函数才会被调用。示例:
1
2
3
4
5
6
7Optional<String> optionalValue = Optional.of("Hello");
String value = optionalValue.orElseGet(() -> expensiveOperation());
System.out.println(value); // 输出:Hello
Optional<String> emptyOptional = Optional.empty();
String computedValue = emptyOptional.orElseGet(() -> expensiveOperation());
System.out.println(computedValue); // 调用 expensiveOperation() 方法,并输出其返回值orElseThrow(Supplier<? extends X> exceptionSupplier)
:如果包含的值存在,则返回该值;如果不存在,则抛出指定的异常。通过提供一个exceptionSupplier来生成异常对象。示例:
1
2
3
4
5
6Optional<String> optionalValue = Optional.of("Hello");
String value = optionalValue.orElseThrow(() -> new IllegalStateException("Value not found"));
System.out.println(value); // 输出:Hello
Optional<String> emptyOptional = Optional.empty();
String computedValue = emptyOptional.orElseThrow(() -> new IllegalStateException("Value not found")); // 抛出异常ifPresent(Consumer<? super T> consumer)
:接受一个 Consumer 函数作为参数,并在包含的值存在时执行该函数。该方法无返回值。示例:
1
2
3
4
5Optional<String> optionalValue = Optional.of("Hello");
optionalValue.ifPresent(value -> System.out.println("Value is present: " + value)); // 输出:Value is present: Hello
Optional<String> emptyOptional = Optional.empty();
emptyOptional.ifPresent(value -> System.out.println("Value is present: " + value)); // 由于值不存在,所以不执行任何操作
最佳实践
1、不要使用Optional
作为Java Bean实例域的类型
即避免以下这种代码:1
2
3
4
5
6// AVOID
public class Customer {
[access_modifier] [static] [final] Optional<String> zip;
[access_modifier] [static] [final] Optional<String> telephone = Optional.empty();
...
}
因为 Optional
没有实现Serializable接口(不可序列化)
2、不要把容器类型包装在Optional
中
即避免:1
2
3
4
5
6// AVOID
public Optional<List<String>> fetchCartItems(long id) {
Cart cart = ... ;
List<String> items = cart.getItems(); // this may return null
return Optional.ofNullable(items);
}
因为容器类都有自己空值设计,如 Collections.emptyList() Collections.emptySet() Collections.emptyMap() Stream.empty()
等:1
2
3
4
5
6// PREFER
public List<String> fetchCartItems(long id) {
Cart cart = ... ;
List<String> items = cart.getItems(); // this may return null
return items == null ? Collections.emptyList() : items;
}
3、不要给Optional
对象赋值 null
避免:1
2
3
4
5// AVOID
public Optional<Cart> fetchCart() {
Optional<Cart> emptyCart = null;
...
}
而应该用 Optional.empty()
表达空值:1
2
3
4
5// PREFER
public Optional<Cart> fetchCart() {
Optional<Cart> emptyCart = Optional.empty();
...
}
4、尽量使用Optional
提供的快捷API避免手写条件语句
代码更简洁。
5、使用 equals
而不是 ==
来比较 Optional
的值Optional
的 equals
方法已经实现了内部值比较。
6、对于可能是空值的函数返回使用Optional
对于读取值类型的函数使用是很好的实践。
参考
[1] https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
[2] https://zhuanlan.zhihu.com/p/128481434
后记
首发于 silencezheng.top,转载请注明出处。