zoukankan      html  css  js  c++  java
  • java代码之美(16) ---Java8 Optional

    摘自:https://www.cnblogs.com/qdhxhz/p/12056745.html

    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)
     
  • 相关阅读:
    Linux下使用mtr做路由图进行网络分析
    PHP使用AJAX返回登录成功信息完整参考代码
    ajax提交表单数据不跳转
    帝国cms常用变量总结
    2020软件工程作业04
    2020软件工程作业03
    疑问
    2020软件工程02
    疑问
    2020软件工程作业01
  • 原文地址:https://www.cnblogs.com/xichji/p/12340171.html
Copyright © 2011-2022 走看看