java8新特性→Optional:适用于层级处理非空判断(依赖上一步操作)的场合

Optional入门

Optional是jdk1.8引入的类型,Optional是一个容器对象,它包括了我们需要的对象,使用isPresent方法判断所包含对象是否为空,isPresent方法返回false则表示Optional包含对象为空,否则可以使用get()取出对象进行操作。

Optional的优点是:

1、提醒你非空判断。

2、将对象非空检测标准化。

//of():为非null的值创建一个Optional
Optional<String> optional = Optional.of("bam");
// isPresent(): 如果值存在返回true,否则返回false
optional.isPresent();           // true
//get():如果Optional有值则将其返回,否则抛出NoSuchElementException
optional.get();                 // "bam"
//orElse():如果有值则将其返回,否则返回指定的其它值
optional.orElse("fallback");    // "bam"
//ifPresent():如果Optional实例有值则为其调用consumer,否则不做处理
optional.ifPresent((s) -> System.out.println(s.charAt(0)));     // "b"

使用案例

//修改 
@Test 
public void testUpdate() { 
    Optional<CmsPage> optional = cmsPageRepository.findOne("5b17a34211fe5e2ee8c116c9"); 
    if(optional.isPresent()){ 
        CmsPage cmsPage = optional.get(); 
        cmsPage.setPageName("测试页面01"); 
        cmsPageRepository.save(cmsPage); 
    } 
}

Optional API

Optional提供很多有用的方法,这样我们就不用显式进行空值检测。Optional 类的引入很好的解决空指针异常。

Optional API地址:https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

static <T> Optional<T>    ofNullable(T value):当value值非空时,则返回一个非空的Optional,否则返回一个空的Optional

<U> Optional<U>   map(Function<? super T,? extends U> mapper):如果value值存在,则执行提供的映射函数,如果结果不为空,返回一个非空的Optional

T  orElse(T other):如果value值存在则返回value值,如果不存在,则返回other。

<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier):如果value值存在,则返回,如果不存在,则抛出一个由Supplier创建的异常。

 void  ifPresent(Consumer<? super T> consumer):如果value值存在,则调用Consumer接口(执行Lambda表达式或方法引用),否则什么都不做。

 Optional<T> filter(Predicate<? super T> predicate):如果值存在且值匹配predicate,返回一个非空的Optional,否则返回一个空的Optional。

 T  orElseGet(Supplier<? extends T> other):如果值存在,则返回该值,否则调用other并返回调用的结果

 Optional API的应用

善用 Optional 可以使我们代码中很多繁琐、丑陋的设计变得十分优雅。

使用 Optional,我们就可以把下面这样的代码进行改写。

public static String getName(User u) {
    if (u == null || u.name == null)
        return "Unknown";
    return u.name;
}

不过,千万不要改写成这副样子。

public static String getName(User u) {
    Optional<User> user = Optional.ofNullable(u);
    if (!user.isPresent())
        return "Unknown";
    return user.get().name;
}

这样改写非但不简洁,而且其操作还是和第一段代码一样。无非就是用 isPresent 方法来替代 u==null。这样的改写并不是 Optional 正确的用法,我们再来改写一次。

public static String getName(User u) {
    return Optional.ofNullable(u)
                    .map(user->user.name)
                    .orElse("Unknown");
}

这样才是正确使用 Optional 的姿势。那么按照这种思路,我们可以安心的进行链式调用,而不是一层层判断了。看一段代码:

public static String getChampionName(Competition comp) throws IllegalArgumentException {
    if (comp != null) {
        CompResult result = comp.getResult();
        if (result != null) {
            User champion = result.getChampion();
            if (champion != null) {
                return champion.getName();
            }
        }
    }
    throw new IllegalArgumentException("The value of param comp isn't available.");
}

让我们看看经过 Optional 加持过后,这些代码会变成什么样子。

public static String getChampionName(Competition comp) throws IllegalArgumentException {
    return Optional.ofNullable(comp)
            .map(Competition::getResult)  // 相当于c -> c.getResult(),下同
            .map(CompResult::getChampion)
            .map(User::getName)
            .orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available."));
}

还有很多不错的使用姿势,比如字符串为空则不打印可以这么写:

string.ifPresent(System.out::println);

Optional 的魅力还不止于此,Optional 还有一些神奇的用法,比如 Optional 可以用来检验参数的合法性。

public void setName(String name) throws IllegalArgumentException {
    this.name = Optional.ofNullable(name)
                        .filter(User::isNameValid)
                        .orElseThrow(()->new IllegalArgumentException("Invalid username."));
}

 这样写参数合法性检测,应该足够优雅了吧。

 不过这还没完,上面的两个例子其实还不能完全反应出 Optional 的设计意图。事实上,我们应该更进一步,减少 Optional.ofNullable 的使用。为什么呢?因为 Optional 是被设计成用来代替 null 以表示不确定性的,换句话说,只要一段代码可能产生 null,那它就可以返回 Optional。而我们选择用 Optional 代替 null 的原因,是 Optional 提供了一个把若干依赖前一步结果的处理结合在一起的途径。

 Optional应用建议

Optional 就像一个处理不确定性的管道,我们在一头丢进一个可能是 null 的东西(接口返回结果),经过层层处理,最后消除不确定性。Optional 在过程中保留了不确定性,从而把对 null 的处理移到了若干次操作的最后,以减少出现 NPE 错误的可能。于是,Optional 应用的建议也呼之欲出了:

  1. 适用于层级处理(依赖上一步操作)的场合

  2. 产生对象的方法若可能返回 null,可以用 Optional 包装。

  3. 尽可能延后处理 null 的时机,在过程中使用 Optional 保留不确定性。

  4. 尽量避免使用 Optional 作为字段类型。

 
原文地址:https://www.cnblogs.com/zwh0910/p/14790086.html