Optional类型

Optional类型

optional<T>对象是一种包装器对象,要么包装了类型T对象,要么没有包装任何对象。对于第一种情况,称这种值为存在的。Optional<T>类型被当做一种更安全的方式,用来替代类型T的引用,这种引用要么引用某个对象,要么为null。但是,它只有在正确使用的情况下才会更安全。

使用Optional值

有效地使用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。

不适合使用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值

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。

利用flatMap来构建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));
    }
}
发布了861 篇原创文章 · 获赞 2275 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/cold___play/article/details/105091423