• java代码之美(16) ---Java8 Optional


    Java8 Optional

    一句话介绍Optional类:使用JDK8的Optional类来防止NullPointerException(空指针异常)问题

    一、前言

    在我们开放过程中,碰到的异常中NullPointerException必然是排行第一的。所以在平时编码中,我们会时时的判断null

    public void saveCity(City city) {
            if (city != null) {
                String cityName = city.getCityName();
                if (cityName != null) {
                    String code = cityDao.findCodeByName(cityName);
                    city.setCode(code);
                    cityDao.save(city);
                }
            }
        }
    

    虽然上面代码变得更加安全,但是过多嵌套 if 语句降低代码整体可读性,提高复杂度。我们可以优化下代码

        public void saveCity(City city) {
            if (city == null) {
                return;
            }
            String cityName = city.getCityName();
            if (cityName == null) {
                return;
            }
            String code = cityDao.findCodeByName(cityName);
            city.setCode(code);
            cityDao.save(city);
        }
    

    这样还可以,但我们通过Optional变的更简洁

        public void saveCity(City city) {
            //就一行 city不为空返回 城市名称 否则直接返回空
            Optional<String> roleOpt = Optional.ofNullable(city).map(City::getCityName);
            //如果容器中 不为空
            if (roleOpt.isPresent()) {
                String code = cityDao.findCodeByName(roleOpt.get());
                city.setCode(code);
                cityDao.save(city);
            }
        }
    

    这样,我们仅需要对我们关心的做一次校验,省却了前面的一系列的检验操作。


    二、Optional API

    概念 Optiona本质是一个容器,容器中存在为null或者不包含非null值的容器对象。提供了一系列的方法供我们判断该容器里的对象是否存在。

    1、JDK源码

    /**
     * final修饰代表不能被子类继承
     */
    public final class Optional<T> {
        /**
         * 创建一个空容器
         */
        private static final java.util.Optional<?> EMPTY = new java.util.Optional<>();
    
        /**
         * 传入的值
         */
        private final T value;
    
        /**
         * 构造函数私有化 说明不能被外部new
         */
        private Optional() {
            this.value = null;
        }
    
        /**
         * 私有化构造函数
         */
        private Optional(T value) {
            this.value = Objects.requireNonNull(value);
        }
    
        /**
         * 获取空容器
         */
        public static <T> java.util.Optional<T> empty() {
            @SuppressWarnings("unchecked")
            java.util.Optional<T> t = (java.util.Optional<T>) EMPTY;
            return t;
        }
    
    
        /**
         * 传入的对象不能为空 否则抛异常
         */
        public static <T> java.util.Optional<T> of(T value) {
            return new java.util.Optional<>(value);
        }
    
        /**
         * 传入的对象可以为空
         */
        public static <T> java.util.Optional<T> ofNullable(T value) {
            return value == null ? empty() : of(value);
        }
    
        /**
         * 获取容器对象的方法 注意 如果用这个方法则代表容器中一定有对象,否则抛异常
         */
        public T get() {
            if (value == null) {
                throw new NoSuchElementException("No value present");
            }
            return value;
        }
    
        /**
         * 判断容器对象是否为空
         */
        public boolean isPresent() {
            return value != null;
        }
    
        /**
         * 如果容器对象为空 则返回当前对象
         */
        public T orElse(T other) {
            return value != null ? value : other;
        }
    
        //==========有关下面这几个JDK8自带的函数式接口的作用,上一篇博客有详细说明,这里就不多说了。
    
        /**
         * 传入Consumer编程式接口参数
         */
        public void ifPresent(Consumer<? super T> consumer) {
            if (value != null)
                consumer.accept(value);
        }
    
        /**
         * 传入Predicate编程式接口参数
         */
        public java.util.Optional<T> filter(Predicate<? super T> predicate) {
            Objects.requireNonNull(predicate);
            if (!isPresent())
                return this;
            else
                return predicate.test(value) ? this : empty();
        }
    
        /**
         * 传入Function编程式接口参数
         */
        public <U> java.util.Optional<U> map(Function<? super T, ? extends U> mapper) {
            Objects.requireNonNull(mapper);
            if (!isPresent())
                return empty();
            else {
                return java.util.Optional.ofNullable(mapper.apply(value));
            }
        }
    
        /**
         * 传入Function编程式接口参数
         */
        public <U> java.util.Optional<U> flatMap(Function<? super T, java.util.Optional<U>> mapper) {
            Objects.requireNonNull(mapper);
            if (!isPresent())
                return empty();
            else {
                return Objects.requireNonNull(mapper.apply(value));
            }
        }
    
        /**
         * 传入Supplier编程式接口参数
         */
        public T orElseGet(Supplier<? extends T> other) {
            return value != null ? value : other.get();
        }
    
        /**
         * 传入Supplier编程式接口参数
         */
        public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
            if (value != null) {
                return value;
            } else {
                throw exceptionSupplier.get();
            }
        }
    }
    

    2、创建Optional对象

    通过上面源码可以看出,Optional的构造函数都是私有化的,无法直接new对象。它这边提供了3个静态方法获取对象。

    1、创建一个一定是空的Optional容器

    Optional<Car> optCar = Optional.empty();
    

    2、创建一个一定是非空值Optional容器(传入的对象不可以为null,否则抛出NullPointerException)

    Optional<Car> optUser = Optional.of(user);
    

    3、创建一个可能是空也可能不为空的Optional容器(传入的对象可以为null)

    Optional<Car> optUser = Optional.ofNullable(user);
    

    3、总结常用方法

    1、isPresent()        //有值则返回true
    2、get():             //值存在时返回值,否则抛出一个NoSuchElement异常(所以调这个,一般先判断上面方法返回是否为true)
    3、orElse(T other)    //值存在时返回值,否则返回一个默认值
    4、ifPresent(Consumer<T> block)             //会在值存在的时候执行给定的代码块
    5、orElseThrow(Supplier<? extends X> exceptionSupplier)  //与get()类似,不同的是可以自定义异常类型
    6、orElseGet(Supplier<? extends T> other)   //orElse方法的延迟调用版,Supplier方法只有在Optional对象不含值时才执行调用
    7、map/flatMap/filter                       //与Stream中用法类似
    

    三、完整的示例

    这里写一个针对以上API都涉及到的Demo,这个例子明白了,那么Optional的使用也就都清楚了。

    代码

    public class OptionalDemo {
        public static void main(String[] args) {
            //1、创建Optional实例,传入的对象不能为null
            Optional<String> nameOptional = Optional.of("张三");
    
            //2、创建Optional实例,传入对象可以为null,也可以不weinull
            Optional emptyOptional = Optional.ofNullable(null);
    
            //3、isPresent方法用来检查Optional实例是否有值。
            if (nameOptional.isPresent()) {
                //调用get()返回Optional值。
                System.out.println("1、" + nameOptional.get());
            }
    
            try {
                //4、在Optional实例上调用get()抛出NoSuchElementException。
                System.out.println("2、" + emptyOptional.get());
            } catch (NoSuchElementException ex) {
                System.out.println("3、异常" + ex.getMessage());
            }
    
            //
            //5、如果Optional值不为空,lambda表达式会处理并在其上执行操作。(这里x代表就是nameOptional中的对象)
            nameOptional.ifPresent((x) -> {
                System.out.println("4、字符串长度为: " + x.length());
            });
    
            //6、如果有值orElse方法会返回Optional实例,没值则返回当前值
            System.out.println("5、"+ emptyOptional.orElse("如果是空容器则返回李四"));
            System.out.println("6、"+nameOptional.orElse("如果是空容器则返回王五"));
    
            //7、orElseGet与orElse类似,区别在于传入的参数不同,一个是直接传入对象,这个是传入Supplier函数式接口
            System.out.println("7、" + emptyOptional.orElseGet(() -> "李四"));
            System.out.println("8、" + nameOptional.orElseGet(() -> "王五"));
    
            try {
                //8、如果是空容器,则可以抛出自定义异常。
                emptyOptional.orElseThrow(() -> new NullPointerException("空容器异常"));
            } catch (Throwable ex) {
                System.out.println("9、" + ex.getMessage());
            }
    
            Optional<String> ageOptional = Optional.of("10");
            //9、这里入参是Function,所以可以转换容器中的对象 好比将String对象转为Integer对象
            Optional<Integer> age = ageOptional.map((value) -> Integer.parseInt(value));
            /**
             * 10、flatMap与map(Funtion)非常相似,不同在于 map返回可以将String对象转为Integer对象,但flatMap转换后一定还是String对象
             */
            Optional<String> upperName = nameOptional.flatMap((value) -> Optional.of(value.toUpperCase()));
    
            //11、filter方法检查Optiona值是否满足给定条件。如果满足返回Optional实例值,否则返回空Optional。
            Optional<String> longName = nameOptional.filter((value) -> value.length() > 6);
            System.out.println("10、" + longName.orElse("longName容器的名字长度小于6位"));
    
            //12、另一个示例,Optional满足给定条件。
            Optional<String> anotherName = Optional.of("乌啦啦市长公主");
            Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
            System.out.println("11、" + shortName.orElse("anotherName容器的名字长度小于6位"));
    
        }
    }
    
    

    运行结果


    参考

    1、JDK8新特性之:Optional

    2、Optional类包含的方法介绍及其示例



    你如果愿意有所作为,就必须有始有终。(26)
    
  • 相关阅读:
    Azure 虚拟机安全加固整理
    AzureARM 使用 powershell 扩容系统磁盘大小
    Azure Linux 云主机使用Root超级用户登录
    Open edX 配置 O365 SMTP
    powershell 根据错误GUID查寻错误详情
    azure 创建redhat镜像帮助
    Azure Powershell blob中指定的vhd创建虚拟机
    Azure Powershell 获取可用镜像 PublisherName,Offer,Skus,Version
    Power BI 连接到 Azure 账单,自动生成报表,可刷新
    Azure powershell 获取 vmSize 可用列表的命令
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/12056745.html
Copyright © 2020-2023  润新知