optional<T>
对象是一种包装器对象,要么包装了类型T对象,要么没有包装任何对象。对于第一种情况,称这种值为存在的。Optional<T>类型被当做一种更安全的方式,用来替代类型T的引用,这种引用要么引用某个对象,要么为null。但是,它只有在正确使用的情况下才会更安全。
有效地使用Optional的关键是要使用这样的方法:它在值不存在的情况下会产生一个可替代物品,而只有在值存在的情况下才会使用这个值。
通常,在没有任何匹配时,我们会希望使用某种默认值,可能是空字符串:
String result = optionalString.orElse("");
//The wrapped string, or "" if none
你还可以调用代码来计算默认值:
String result = optionlString.orElseGet(() -> Locale.getDefault().getDisplayName());
//The function is only called when needed
或者可以在没有任何值时抛出异常:
String result = optionalString.orElseThrow(IllegalAccessException::new);
另一种使用可选值的策略是只有在其存在的情况下才消费该值。
ifPresent方法会接受一个函数。如果该可选值存在,那么它会被传递给该函数。否则,不会发生任何事情:
optionalString.ifPresent(v -> Process v);
如果在该值存在的情况下想要将其添加到某个集中,那么就可以调用:
optionalString.ifPresent(v -> results.add(v));
或者直接调用:
optionalString.ifPresent(results::add);
当调用ifPresent时,从该函数不会返回任何值。如果想要处理函数的结果,应该使用map:
Optional<Boolean> added = optionalString.map(results::add);
方法 | 说明 |
---|---|
T orElse(T other) | 产生这个Optional的值,或者在该Optional为空时,产生other |
T orElseGet(Supplier<? extends T> other) | 产生这个Optional的值,或者在该Optional为空时,调用other的结果 |
<X extends Throwabled> T orElseThrow(Supplier<? extends X> exceptionSupplier) | 产生这个Optional的值,或者在该Optional为空时,抛出调用exceptionSupplier的结果 |
void ifPresent(Consumer<? super T> consumer) | 如果该Optional不为空,那么就将它的值传递给consumer |
<U> Optional<U> map(Function<? super T, ? extends U> mapper) | 产生将该Optional的值传递给mapper后的结果,只要这个Optional不为空且结果不为null,否则产生一个空Optional。 |
get方法会在Optional值存在的情况下获得其中包装的元素,或者在不存在的情况下抛出一个NoSuchElementException对象。因此:
Optional<T> optionalValue = ...;
optionalValue.get().someMethod();
//并不比下面的方式更安全
T value = ...;
value.someMethod();
ifPresent方法会报告某个Optional<T>对象是否具有一个值,但是
if(optionalValue.isPresent())
optionalValue.get().someMethod();
//并不比下面的方法更容易处理
if(value != null)
value.someMethod();
方法 | 说明 |
---|---|
T get() | 产生这个Optional的值,或者在该Optional为空时,抛出一个NoSuchElementException |
boolean isPresent() | 如果该Optional不为空,则返回true |
Optional.of(result) 和 Optional.empty()
public static Optional<Double> inverse(Double x) {
return x == 0 ? Optional.empty() : Optional.of(1 / x);
}
ofNullable方法被用啦作为可能出现的null值和可选值之间的桥梁:
Optional.ofNullable(obj)会在obj不为null的情况下返回Optional.of(obj),否则会返回Optional.empty()。
方法 | 说明 |
---|---|
static <T> Optional<T> of(T value) static <T> Optional<T> ofNullable(T value) | 产生一个具有给定值的Optional。如果value为null,那么第一个方法抛出一个具有给定值的NullPointerExcepion对象,而第二个方法会产生一个空optional。 |
static <T> Optional<T> empty() | 产生一个空Optional。 |
假如有一个可以产生Optional对象的方法f、并且目标类型T具有一个可以产生Optional对象的方法g。如果他们都是普通的方法,那么你可以通过调用s.f().g()来将他们组合起来。但是这种组合没法工作,因为s.f()的类型为Optional<T>,而不是T。因此,需要调用:
Optional<U> result = s.f().flatMap(T::G);
如果s.f()的值存在,那么g就可以应用到它上面。否则,就会返回一个空Optional。
很明显,如果有更多的可以产生Optional值的方法或Lambda表达式,那么就可以重复此过程。你可以直接将flatMap的调用链接起来,从而构建由这些步骤构成的管道,只有所有步骤都成功时,该管段才会成功。
package pers.zhang;
import java.util.*;
/**
* @Author: acton_zhang
* @Date: 2020/3/25 11:49 上午
* @Version 1.0
*/
public class OptionalTest {
public static void main(String[] args) {
String[] strs = {"one", "two", "three", "four", "five"};
List<String> wordList = Arrays.asList(strs);
Optional<String> o = wordList.stream().filter(s -> s.contains("o")).findFirst();
System.out.println(o.orElse("No word contains o"));
Optional<String> optionalString = Optional.empty();
String result = optionalString.orElse("N/A");
System.out.println("result:" + result);
result = optionalString.orElseGet(() -> Locale.getDefault().getDisplayName());
System.out.println("result:" + result);
try {
result = optionalString.orElseThrow(IllegalAccessException::new);
System.out.println("result:" + result);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
optionalString = wordList.stream().filter(s -> s.contains("e")).findFirst();
optionalString.ifPresent(s -> System.out.println(s + "contains e"));
Set<String> results = new HashSet<>();
optionalString.ifPresent(results::add);
Optional<Boolean> added = optionalString.map(results::add);
System.out.println(added);
System.out.println(inverse(4.0).flatMap(OptionalTest::squareRoot));
System.out.println(inverse(-1.0).flatMap(OptionalTest::squareRoot));
System.out.println(inverse(0.0).flatMap(OptionalTest::squareRoot));
Optional<Double> result2 = Optional.of(-4.0)
.flatMap(OptionalTest::inverse)
.flatMap(OptionalTest::squareRoot);
System.out.println(result2);
}
public static Optional<Double> inverse(Double x) {
return x == 0 ? Optional.empty() : Optional.of(1 / x);
}
public static Optional<Double> squareRoot(Double x) {
return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
}
}