美文网首页
Java8特性之Optional

Java8特性之Optional

作者: 文景大大 | 来源:发表于2020-05-21 21:19 被阅读0次

    一、什么是Optional

    Optional从名字上看,意思应该是可选项的意思,那么在Java8的实际使用中,我们就是使用它来表示一个可以为空的对象,给开发者提供了一种可以不用判断非空的程序写法,更加地易读和优雅。

    比如,我们创建两个方法,分别用来获取空对象和非空对象:

    private Person getNullPerson(){
            return null;
    }
    private Person getPerson(){
            return new Person("mason",22, 3500.0);
    }
    

    如果我们不使用Optional,那么我们可能会写出这样的代码:

        @Test
        public void test01(){
            Person person = getNullPerson();
            // 直到使用的时候才报出NPE
            log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
        }
    

    这段代码很容易就出现NPE,所以我们一般这样写:

        @Test
        public void test01(){
            Person person = getNullPerson();
            if(person != null){
                // 每次使用都需要进行非空判断,非常繁琐,容易遗忘
                log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
            }
        }
    

    可以看到,这样写比较繁琐,我们完全可以使用Optional来完成这个例子:

        @Test
        public void test03(){
            // 提前报出NPE问题,而不是等到使用的时候才发现
            Optional<Person> optional = Optional.of(getNullPerson());
            Person person = optional.get();
            log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
        }
    

    在如上的例子中,只要Optional.of的对象是空的,那么就会提前抛出NPE问题,而不是等到使用的时候才发现。

    这么一看,代码好像也没有变得更加精简,Optional也没有体现它的优雅和简洁。别着急,我们先来看看Optional的一些常规用法。

    二、Optional的使用

    • of的用法;

      在上面的案例中,我们就已经使用了该方法,获取一个Optional<T>的对象,倘若对象为空,则of方法直接就抛出NPE;对象不为空的话,我们可以通过get来获取该非空T对象;

          @Test
          public void test02(){
              // 正常的使用
              Optional<Person> optional = Optional.of(getPerson());
              Person person = optional.get();
              log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
          }
      
    • empty的用法;

      我们可以通过调用empty来获取一个空的Optional<T>对象,如果直接使用该空对象尝试获取T对象的话,就会抛出java.util.NoSuchElementException: No value present,通常情况下,empty只会在声明JavaBean中的属性为空的Optional<T>时使用。

          @Test
          public void test04(){
              // 创建一个空的实例
              Optional<Person> optional = Optional.empty();
              // 如下语句抛出java.util.NoSuchElementException: No value present
              Person person = optional.get();
              log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
          }
      
    • ofNullable的用法;

      在上面of的用法中,不允许对象为空,而有的时候,我们仍然需要这个为空的Optional<T>对象,那么就可以使用ofNullable。

          @Test
          public void test05(){
              // 创建一个可以为空的实例
              Optional<Person> optional = Optional.ofNullable(getNullPerson());
              // 如下语句抛出java.util.NoSuchElementException: No value present
              Person person = optional.get();
              log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
          }
      
    • isPresent的用法;

      通常ofNullable和isPresent都是配合使用的。

          @Test
          public void test07(){
              Optional<Person> optional = Optional.ofNullable(getNullPerson());
              if(optional.isPresent()){
                  Person person = optional.get();
                  log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
              }
          }
      
    • orElse的用法;

      如果我们使用isPresent,仿佛又回到了!=null的老路子上去了,所以,我们还可以在Optional<T>为空的时候,指定一个默认的非空对象。

          @Test
          public void test10(){
              // 创建一个可以为空的实例
              Person person = Optional.ofNullable(getNullPerson()).orElse(getDefaultPerson());
              log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
          }
      
      private Person getDefaultPerson(){
              return new Person("default",20, 3000.0);
          }
      
    • orElseGet的用法;

      和orElse的作用类似,区别是可以指定额外的处理逻辑。

          @Test
          public void test11(){
              // 创建一个可以为空的实例
              Person person = Optional.ofNullable(getNullPerson()).orElseGet(() -> new Person("Jack", 33, 5501.1));
              log.info("员工的姓名为:{},年龄为:{},薪水为:{}", person.getName(), person.getAge(), person.getSalary());
          }
      
    • map的用法;

      我们还可以对T对象进行一些流式处理。

          @Test
          public void test12(){
              // 创建一个可以为空的实例
              Integer age = Optional.ofNullable(getNullPerson())
                      .map((x) -> x.getAge())
                      .map((y) -> y*2)
                      .orElse(45);
              log.info("员工的年龄为:{}", age);
          }
      

    三、为什么要使用Optional

    我们在日常的使用中,经常会遇到这样的场景:

    @Data
    public class Home {
        private String address;
    
        public Home(){}
    
        public Home(String address){
            this.address = address;
        }
    }
    
    @Data
    public class Person {
        private String name;
        private Integer age;
        private Double salary;
        private Home home;
    
        public Person(){}
    
        public Person(String name, Integer age, Double salary){
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
    }
    
        @Test
        public void test15(){
            Person person = getNullPerson();
            if(person != null){
                Home home = person.getHome();
                if(home != null){
                    String address = home.getAddress();
                    log.info("员工的地址为:{}", address);
                }
            }
        }
    

    我们尝试打印Person中的Home中的address属性,不得不做两次非空校验,而且,对于Person和Home任一为空的情况没有做任何的处理,否则,将还会多出来两个else语句,十分繁琐,冗余。

    但是如果我们使用Optional会怎样?

    @Data
    public class Person {
    
        private String name;
        private Integer age;
        private Double salary;
        private Optional<Home> home = Optional.empty();
    
        public Person(){}
    
        public Person(String name, Integer age, Double salary){
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
    }
    
        @Test
        public void test14(){
            // 创建一个可以为空的实例
            String address = Optional.ofNullable(getNullPerson()).orElse(getDefaultPerson())
                    .getHome().orElseGet(() -> new Home("China!!!")).getAddress();
            log.info("员工的地址为:{}", address);
        }
    

    在上面的例子中,我们完全实现了test15的功能,除此之外,还对Person为空和Home为空的情况做了默认值设置,大大提升了易读性,变得更加优雅。

    相关文章

      网友评论

          本文标题:Java8特性之Optional

          本文链接:https://www.haomeiwen.com/subject/dgcxahtx.html