前沿

到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。

我们在开发中经常碰到的NullPointerException.假设我们有两个类,他们的UML类图如下图所示

java QueryWrapper不为空_java

在这种情况下,有如下代码user.getAddress().getProvince();`

这种写法,在user为null或者user.getAddress()为null时,是有可能报NullPointerException异常的。为了解决这个问题,于是采用下面的写法

if(user!=null){
    Address address = user.getAddress();
    if(address!=null){
        String province = address.getProvince();
    }
}

这种写法是比较丑陋的,为了避免上述丑陋的写法,让丑陋的设计变得优雅。所以在 JDK8 中引入了 Optional 来解决空指针异常的问题,养成使用 Optional 的习惯后你可以写出更优雅的代码来避免空指针异常。并且在很多函数式编程相关的 API 中也都用到了 Optional

创建Optional对象

方法

描述

public static<T> Optional<T> empty()

创建一个空的Optional对象

public static <T> Optional<T> ofNullable(T value)

传进一个值创建一个Optional对象如果对象是空的那么返回一个 empty()

public static <T> Optional<T> of(T value)

传进一个值创建一个Optional对象如果对象是空的,那么报异常NullPointerException

String name = "John";
Optional<String> opt = Optional.ofNullable(name);

Optional API

方法

描述

public T get()

如果此可选项中存在值,则返回该值,否则将抛出NoTouchElementException。

public boolean isPresent()

如果值不是null,则返回true,否则返回false

public void ifPresent(Consumer<? super T> consumer)

如果值不是null那么获取consumer返回的值

public Optional<T> filter(Predicate<? super T> predicate)

如果对象为空那么返回当前对象, 如果对象不是空那么执行predicate判断条件,条件为true返回当前对象否则返回 empty()

public<U> Optional<U> map(Function<? super T, ? extends U> mapper)

如果对象为空那么返回empty(),如果对象不为空那么执行mapper返回是一个值,然后会自动通过Optional.ofNullable进行封装

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)

和map一样但是不同的是mapper返回必须是Optional对象,不能返回为null, 否则报错NullPointerException

public T orElse(T other)

如果不是空那么返回当前值,否则返回other

public T orElseGet(Supplier<? extends T> other)

如果不是空那么返回当前值, 否则返回other处理结果

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X

如果不是空那么返回当前值,否则返回指定的异常报错

public boolean equals(Object obj)

判断对象是否是当前引用如果是返回true,如果不是继续判断是否是Optional对象如果不是返回false,然后在判断是否两个Optional的value是否相等

案例演示:

Optional<String> username = Optional.ofNullable(getUserById(id))//数据查询
		.map(user -> user.getUsername())
		.map(name -> name.replace('_', ' '));

//以上调用链只要有一个为空那么就会返回empty()我们可以通过username.orElse("默认值")或者username.isPresent()方式来处理
if(username .isPresent()){ //如果username 不是空那么执行if代码块

}
//如果username对象不是空那么返回原值,如果是空返回默认值
System.out.println("Username is: " + username.orElse("Unknown"));

至于其他的可以直接看源码进行解读和使用,源码比较简单

扩展

一个挺流行的说法是,Optional 能用来解决NullPointerException,呼吁多用 Optional 来避免NullPointerException。但NullPointerException 的本质问题是,在一个不该是 null 的地方,传进来了 null,这是一种异常,不是程序可正常处理的情况。

这个时候,不论检查 null 打印 log,还是抛NullPointerException 后,都应终止,不再执行下去。NullPointerException 不一定是坏事,实践中比那些瞎 catch exception,然后自作聪明包装成另一种异常的代码要容易追踪。

Optional 只是 data type,不能从根本上避免异常。如果你的 function 只在非空的参数下才可执行,别人传了 null 进来,有什么办法呢?Optional 也不适合放在函数参数中,需要表示参数是否可空时,可使用 annotation。

在代码块中,如果只是要 check 一层变量是不是 null,不论是 if == null,还是包上 optional,本质上都不能避免分支,该检查的地方都不能省。有的情况下 Optional 能少写几行,但读起来还不如 if 明了。速度上来说,optional 也比 if 开销大。

但当函数 return 值可能为 null 时,包上 optional 不仅可以清楚的让调用者知道可能为空,还方便在链式调用时不必逐层判断,一口气写下来,就爽很多。这时就是很有用的,也是其原本的设计目的。

也就是: Optional主要用于作为方法返回类型,表示说我这个方法可能返回是NULL你需要处理下,并且Optional内部提供了处理的方式了, 还有一个好处就是在一个对象调用链比较深的时候,可以比较简短代码的去处理全调用链的空值情况 , 但要是同时处理多个不同任务的空值那么还不如使用if进行处理,如果用Optional就会显得累赘

java QueryWrapper不为空_jvm_02