前言
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 ; } }