java8新特性之Optional

2019-03-17  本文已影响0人  梦想实现家_Z

Optional的出现是为了解决java由来已久的null安全问题,正确的使用Optional会让你的代码写得十分优雅。
1.代码示例

import java.util.Optional;

public class OptionalMain {
    /**
     * User类
     */
    private static class User {

        /**
         * 有参构造函数
         *
         * @param name
         */
        public User(String name) {
            this.name = name;
        }

        /**
         * 名字
         */
        private final String name;

        public String getName() {
            return name;
        }
    }

    /**
     * 1.8之前的写法
     *
     * @param user
     * @return
     */
    private static String getName1(User user) {
        if (user == null) {
            return "Unknow";
        }
        return user.getName();
    }

    /**
     * Optional错误的写法
     *
     * @param user
     * @return
     */
    private static String getName2(User user) {
        Optional<User> optionalUser = Optional.ofNullable(user);
        if (!optionalUser.isPresent()) {
            return "Unknow";
        }
        return optionalUser.get().getName();
    }

    /**
     * Optional正确的使用姿势
     *
     * @param user
     * @return
     */
    private static String getName3(User user) {
        return Optional.ofNullable(user).map(u -> u.getName()).orElse("Unknow");
    }

    /**
     * 主函数
     *
     * @param args
     */
    public static void main(String[] args) {
        String name1 = getName1(null);
        String name2 = getName2(null);
        String name3 = getName3(null);
        System.out.println(name1);
        System.out.println(name2);
        System.out.println(name3);

        User user = new User("Zz");
        name1 = getName1(user);
        name2 = getName2(user);
        name3 = getName3(user);
        System.out.println(name1);
        System.out.println(name2);
        System.out.println(name3);
    }
}

对比上面的代码,正确地使用Optional既能避免过多地null判断,同时让代码显得简短而优雅。

2.API分析

   /**
     * 无参构造函数默认value=null
     */
    private Optional() {
        this.value = null;
    }

   /**
     * 直接通过构造函数的方式必须保证参数不为null
     *
     * @param value
     */
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 要求传入的参数不能为null
     *
     * @param value
     * @param <T>
     * @return
     */
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    /**
     * 默认value为null的Optional
     */
    private static final Optional<?> EMPTY = new Optional<>();

    /**
     * 对外提供获取默认value为null的Optional
     *
     * @param <T>
     * @return
     */
    public static <T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

    /**
     * 根据代码逻辑判断,对参数没有限制,允许为null
     *
     * @param value
     * @param <T>
     * @return
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

从上述源码分析的角度来看,可以得出以下几个结论:
1.private的访问控制符意味着外界不能通过构造函数的方式创建
2.Optional.empty()可以直接创建一个value为空的Optional
3.Optional.of(T value)要求传的参数一定不能为null
4.Optional.ofNullable(T value)对参数是否为null没有限制

2.1Present的使用

import java.util.Optional;

public class OptionalMain {

    private static void testPresent() {

        Optional<String> optional1 = Optional.of("hello");
        //如果value不是null,就会打印
        optional1.ifPresent(System.out::println);
        System.out.println(optional1.isPresent());
        
        Optional<String> optional2 = Optional.ofNullable(null);
        //如果value是null,就不会打印
        optional2.ifPresent(System.out::println);
        System.out.println(optional2.isPresent());
    }

    /**
     * 主函数
     *
     * @param args
     */
    public static void main(String[] args) {
        testPresent();
    }
}

2.2 orElse的使用

public class OptionalMain {

    /**
     * 测试Optional
     */
    private static void testOptional() {
        Optional<String> optional1 = Optional.ofNullable(null);
        //如果value是null就返回hello
        String res1 = optional1.orElse("hello");
        System.out.println(res1);
        //如果value是null就调用指定函数创建一个实例返回
        String res2 = optional1.orElseGet(() -> new String("world"));
        System.out.println(res2);
        try {
            //如果value是null抛出异常
            optional1.orElseThrow(() -> new Exception("异常"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 主函数
     *
     * @param args
     */
    public static void main(String[] args) {
        testOptional();
    }
}

2.3 filter的使用

import java.util.Objects;
import java.util.Optional;

public class OptionalMain {

    /**
     * User类
     */
    private static class User {
        /**
         * 名字
         */
        private String name;

        /**
         * 年龄
         */
        private Integer age;

        /**
         * 有参构造函数
         *
         * @param name
         * @param age
         */
        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public Integer getAge() {
            return age;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "name:" + name + " age:" + age;
        }
    }

    /**
     * 测试filter
     */
    private static User isAdult(User user) throws Exception {
        Optional<User> optional1 = Optional.ofNullable(user);

        /**
         * 过滤name不为null,age大于18岁的user
         */
        return optional1.filter(u -> !Objects.isNull(u.getName()))
                //年龄大于18岁
                .filter(u -> u.getAge() > 18)
                //如果name为null或者age小于18就抛出异常
                .orElseThrow(() -> new Exception("未成年人"));
    }

    /**
     * 主函数
     *
     * @param args
     */
    public static void main(String[] args) throws Exception {
        User user = isAdult(new User("Zz", 20));
        System.out.println(user);

        user = isAdult(new User("Z", 16));
        System.out.println(user);
    }
}

filter和数据库查询语句一样,以一种优雅的编码方式对数据进行过滤。

2.4 map的使用

import java.util.List;
import java.util.Optional;

public class OptionalMain {

    /**
     * User类
     */
    private static class User {
        /**
         * 名字
         */
        private String name;

        /**
         * 年龄
         */
        private Integer age;

        /**
         * 有参构造函数
         *
         * @param name
         * @param age
         */
        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public Integer getAge() {
            return age;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "name:" + name + " age:" + age;
        }
    }

    /**
     * 部门实体类
     */
    private static class Department {
        /**
         * 部门名称
         */
        private String name;

        /**
         * 部门领导
         */
        private User leader;

        /**
         * 部门员工
         */
        private List<User> users;

        /**
         * 有参构造函数
         *
         * @param name
         * @param leader
         * @param users
         */
        public Department(String name, User leader, List<User> users) {
            this.name = name;
            this.leader = leader;
            this.users = users;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public User getLeader() {
            return leader;
        }

        public void setLeader(User leader) {
            this.leader = leader;
        }

        public List<User> getUsers() {
            return users;
        }

        public void setUsers(List<User> users) {
            this.users = users;
        }
    }

    /**
     * 测试map
     */
    private static String getLeaderName(Department department) throws Exception {
        Optional<Department> opt = Optional.ofNullable(department);
        /**
         * 从部门中查找领导名字
         */
        return opt
                //从部门中找出Leader
                .map(dep -> dep.getLeader())
                //从User中找出name
                .map(leader -> leader.getName())
                //如果name为null就抛出异常
                .orElseThrow(() -> new Exception("没有领导"));
    }

   /**
     * 测试flatMap
     */
    private static String getUpperLeaderName(Department department) throws Exception {
        Optional<Department> opt = Optional.ofNullable(department);
        /**
         * 从部门中查找领导名字
         */
        return opt
                //从部门中找出Leader
                .map(dep -> dep.getLeader())
                //从User中找出name
                .map(leader -> leader.getName())
                //flatMap相当于对流水线上的产品再做一次包装
                .flatMap(name -> Optional.of(new User(name.toUpperCase(), 30)))
                //从包装后的产品中再拆解
                .map(leader -> leader.getName())
                //如果name为null就抛出异常
                .orElseThrow(() -> new Exception("没有领导"));
    }

    /**
     * 主函数
     *
     * @param args
     */
    public static void main(String[] args) throws Exception {
        String leaderName = getLeaderName(new Department("部门名字", new User("部门领导名字", 30), null));
        System.out.println(leaderName);

        leaderName = getUpperLeaderName(new Department("部门名字", new User("leaderName", 30), null));
        System.out.println(leaderName);

        leaderName = getLeaderName(new Department("部门名字", null, null));
        System.out.println(leaderName);
    }
}

结束语:以上是关于Optional的一些简单实践。

上一篇下一篇

猜你喜欢

热点阅读