java8的Optional

前言

  java中的null是每位java开发者无法回避的问题,也是无比痛恨的问题。逻辑上明明正常的程序,在运行的时候却偏偏会抛出NullPointException。在做所有的操作之前(set/get/equals等),都必须加上一行"if(xxx != null)"来进行判断,否则有很大概率会在运行时看到一堆NullPointException。另外有些工作经验的程序员都知道,就算本人心里很放心对象不会为null,也必须判断,否则代码上线前的sonar检查一般都是通不过的。

Optional的使用

​   java的创建者在后来也发现了这个问题,对于null,创建者们现在的普遍观点也是认为这是一个失误。所以在java8中对此做出了相应的补救措施,这个补救就是Optional类。

​   通过将对象(空对象/非空对象)放入Optional类中,然后通过Optional提供的API来获取和操作该类,帮助优雅的对null进行相应的处理。而不是在代码中写一大堆类似"if(xxx != null)"的代码。

​   我们应该将需要操作的对象先放入Optional对象中,再进行相应的操作,这就要求我们首先得构建出Optional对象。查看Optional的源码可以发现,该类的所有构造方法均被private修饰,所以需要通过Optional类提供的一些静态方法来构建。常用的静态方法有如下三个:

Optional optional = Optional.of(object); // 如果object==null,会抛出NullPointerException
Optional optional = Optional.ofNullable(object); // 如果object==null,底层调用Optional.Empty()方法创建Optional对象
Optional optional = Optional.empty(); // 返回一个value==null的Optional对象

  通过上述三个方法中的任意一个,都可以得到一个Optional对象,其中常用的是前两个。

​   对于Optional的对象,一般还有两个常用的API,分别是:

boolean isNull = optional.isPresent(); //判断optional中的对象是否为非null对象
Object object = optional.get(); // 从optional中取出放置的对象。如果放置的值为null,那么会抛出NoSuchElementException异常

  下面开始举一个实际的小案例来说明应该如何使用Optional。假设我们有一个student的对象,现在需要调用其getName()方法

Student student = ....; // 通过某种方式(new/db/method等)获得,所以可能为null
// 不使用Optional的方式
if(student != null) { 
    student.getName(); 
}
// 使用Optional的方式
Optional<Student> optional = Optional.ofNullable(student); // 不能使用Optional.of(),因为不确实student是否为null
if(optional.isPresent()) {
    Student stu = optional.get(); // optional.isPresent()为true,说明其中存放的对象不会为null
    stu.getName();
}

  上述代码完美的实现了功能,避免的NullPotionException。但是明显能看到,对于null的判断反而复杂化了,而且从代码的阅读角度来说,这样的代码多了之后,明显对代码的阅读也会带来不小的负担。毕竟java中"get()"这样的方法挺多的(像ThreadLocal等)。

​   所以Optional的使用的正确打开方式明显不是这样的。对比java8中另一大特性Stream来看,我们会发现,java8中特别推崇的一种编码风格就是流式编程。Optional不外如是。

​   下面我们尝试通过流失编程的方式,美化下上述代码。

​   这里引入一个新的API——isElse(object)。一般搭配Optional.ofNullable(object)使用。如果Optional.ofNullable(object)中的object==null,那么就会走isElse作为保底,保证Optional对象中存放的对象一定不为null。所以就可以写出如下代码:

// 流式编程。  orElse返回值是T(Optional<T>)
Optional.ofNullable(student).orElse(new Student()).getName();

  orElse系列方法其实有三个,一般都是配合Optional.ofNullable(object)使用,分别如下:

orElse(T other); // 保底,如果Optional.ofNullable(object)中的object==null,那就返回传入的other
orElseGet(Supplier<? extends T> other); // 保底,如果如果Optional.ofNullable(object)中的object==null,返回传入lambda表达式返回的值
orElseThrow(Supplier<? extends X> exceptionSupplier); // 保底,如果Optional.ofNullable(object)中的object==null,返回传入lambda表达式抛出的异常

  更多的时候,Optional配合Stream可以写出非常简洁的流式编程的代码,代码如下:

public class Test {
    
    public static void main(String[] args) {
        Student student = new Student();
        List<String> collect = Optional.ofNullable(student.getCourses())
                                       .orElse(new ArrayList<>())
                                       .stream().map(s -> s)
                                       .collect(Collectors.toList()); 
    }
    @Data
    static class Student {
        List<String> courses ;
    }
}
posted @ 2020-10-27 17:41  极速战略J  阅读(123)  评论(0)    收藏  举报