• 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 作为字段类型。

     
  • 相关阅读:
    [leetcode-91-Decode Ways]
    [leetcode-72-Edit Distance]
    [leetcode-67-Add Binary]
    [leetcode-137-Single Number II]
    [leetcode-60-Permutation Sequence]
    [leetcode-55-Jump Game]
    [leetcode-18-4Sum]
    [leetcode-15-3Sum]
    [leetcode-47-Permutations II]
    easyui tabs update 强制刷新页面
  • 原文地址:https://www.cnblogs.com/zwh0910/p/14790086.html
Copyright © 2020-2023  润新知