Optional是JDK8引入的新特性,主要用于解决Java程序中对于null的处理。很多时候,调用一个方法获取的返回值为null,不能直接作为参数去调用其他方法,因此需要使用大量的非空判断,特别是在"."运算符中。但往往我们并不能保证100%去对一个值做非空判断,即使都使用判断,也可能会影响代码本身的质量。JDK8引入的Optional则很好的解决了这个问题。
Javadoc中是这样表述Optional类的:
这是一个可以为null的容器对象。如果值存在,则isPresent()方法返回true,并且调用get()方法可以返回这个值。
下面,我将根据源码和例程详细介绍一下Optional的功能和用途。首先需要知道的是,Optional的构造方法是私有的,所以不能使用new Optional<T>()的形式创建Optional对象,Optional中创建了一个EMPTY的单例对象,这个对象没有指定值。
一、Optional主要方法
1. empty()
源码如下:
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
返回一个空的Optional对象,这个对象没有值。
2. of()
源码如下:
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
根据所传入的value返回一个Optional对象,如果value为null,则会跑出空指针异常NullPointException。
3. ofNullable()
源码如下:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
根据value的值返回一个Optional对象,如果value为null,则返回一个没有值的Optional对象EMPTY。
4. get()
源码如下:
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
如果Optional有值,则返回这个值;否则抛出NoSuchElementException异常。
5. isPresent()
源码如下:
public boolean isPresent() {
return value != null;
}
如果Optional对象的值存在,则返回true,否则返回false。
6. ifPresent()
源码如下:
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
如果Optional对象有值则为其调用consumer,否则不做任何处理。Consumer是一个接口,包含一个accept()方法和default域的方法,accept()方法对传入的值进行处理,但没有返回值。Java8中支持不用接口直接通过lambda表达式传入参数。
7. filter()
源码如下:
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
这个方法通过传入的限定条件对Optional对象的值进行过滤。如果Optional有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。可以传入实现了Predicate接口的lambda表达式。
8. map()
源码如下:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
如果有值,则对其执行调用mapping函数得到返回值;如果返回值不为null,则创建包含mapping返回值的Optional作为map()的返回值,否则返回空Optional。
9. flatMap()
源码如下:
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap()和map()类似,区别在于flatMap()中的mapper必须是Optional,调用结束后,flatMap()不会对结果用Optional封装。
10. orElse()
源码如下:
public T orElse(T other) {
return value != null ? value : other;
}
如果Optional对象有值,则返回该值;否则返回指定的值。
11. orElseGet()
源码如下:
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
该方法与orElse()方法类似,其区别在于得到默认值的方法。orElse()是直接传入特定的值作为默认值,而orElseGet()方法可以通过实现Supplier接口的lambda表达式来生成默认值。
12. orElseThrow()
源码如下:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
如果Optional对象有值,则将其返回;否则抛出Supplier接口创建的异常。
以上就是Optional主要的方法,还需要注意的是,Optional还覆写了equals()、hashCode()、toString()方法。
源码如下:
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
以上介绍了Optional中的所有的方法及其实现。下面将介绍一下如何较好的使用Optional解决NullPointException问题。这里,需要注意的是,如何巧妙的使用Optional解决问题。
二、Optional的使用
首先我们看下面一个例子:
@Test
public void _test_badUsed() {
OptionalEntity oe = new OptionalEntity();
Optional<String> value = Optional.ofNullable(oe.getValue());
if (value.isPresent()) {
System.out.println(value.get());
} else {
System.out.println("null");
}
}
在这个例子中,OptionalEntity类定义了一个String类型的value,现在使用Optional的ofNullable获取这个value值,并判断value是否存在,如果存在,则输出这个值。看起来,这个程序并没有什么错误,运行起来也可以通过。但其实这和直接判断value的值是否为空并没有什么区别,显然,这并不是我们想要的。那如何较好的使用Optional呢?接下来,我将来详细介绍Optional的运用。
1. 存在即返回,无则返回默认值。
OptionalEntity oe = new OptionalEntity();
Optional<String> value = Optional.ofNullable(oe.getValue());
String name = value.orElse("default");
System.out.println(name);
2. 存在即返回,无则由lambda表达式生成。
String name1 = value.orElseGet(() -> "default");
System.out.println(name1);
3. 存在才对它做点儿什么。
OptionalEntity oe1 = new OptionalEntity();
Optional<String> value1 = Optional.ofNullable(oe1.getValue());
OptionalEntity oe2 = new OptionalEntity("Hello world!");
Optional<String> value2 = Optional.ofNullable(oe2.getValue());
value1.ifPresent(System.out::println);
value2.ifPresent(System.out::println);
4. map()和flatMap()函数的运用
OptionalEntity oe1 = new OptionalEntity("test");
List<String> values = new ArrayList<>();
values.add("hello");
values.add("world");
values.add("java");
oe1.setValues(values);
Optional<OptionalEntity> opt1 = Optional.of(oe1);
List<String> valueList = opt1.map(oe -> oe.getValues())
.orElse(Collections.emptyList());
valueList.stream().forEach(System.out::println);
String value = opt1.flatMap(oe -> Optional.of(oe.getValue()))
.map(v -> v.toUpperCase()).orElse("null");
System.out.println(value);
注意map()和flatMap()的区别。
5. filter()函数的使用
OptionalEntity oe1 = new OptionalEntity("test");
Optional<String> opt1 = Optional.ofNullable(oe1.getValue());
opt1.filter(v -> v.length() > 6)
.ifPresent(System.out::println);
OptionalEntity oe2 = new OptionalEntity("Hello world, java!");
Optional<String> opt2 = Optional.ofNullable(oe2.getValue());
opt2.filter(v -> v.length() > 6)
.ifPresent(System.out::println);
以上就是我对Optional的总结。在上面的例子中,可以看到Optional经常与Stream、lambda表达式结合使用,这也是JDK8的新特性,而Stream和lambda表达式将在以后进行总结。