Optional类
我们在写Java代码的时候,通常会遇到==NullPointerException==,为了不抛出这个异常,我们一般会写如下代码:
1 | User user = getUserById(id); |
但是很多时候,我们可能会忘记写==if(user!=null)==
如果在开发阶段就发现那还好,但是如果在开发阶段没有测试到问题,等到上线却出了==NullPointerException==画面太美,我不敢继续想下去
为了解决这种尴尬的处境,JDK终于在Java8的时候加入了==Optional==类,Optional的Javadoc介绍:
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
解释:这是一个可以包含或者不包含非null值的容器.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象
构造Optional
JDK提供三个静态方法来构造一个==Optional==:
1.==Optional.of(T value)==:该方法通过一个非null的value来构造一个 Optional,返回的Optional包含了value这个值.对于该方法,传入的参数一定不能为null,否则便会抛出NullPointerException
具体源码如下:
1 | public static <T> Optional<T> of(T value) { |
2.==Optional.ofNullable(T value)==:该方法和of方法的区别在于–>传入的参数可以为 null
但是前面javadoc不是说Optional只能包含非null值吗?我们可以看看ofNullable方法的源码
1 | public static <T> Optional<T> ofNullable(T value) { |
原来该方法会判断传入的参数是否为null,如果为null的话,返回的就是Optional.empty()
3.==Optional.empty()==:该方法用来构造一个空的Optional,即该Optional中不包含值
其实底层实现:如果Optional中的value 为null则该Optional为不包含值的状态,然后在API层面将Optional表现的不能包含null值,使得Optional只存在包含值和不包含值两种状态
具体源码如下:
1 | public static<T> Optional<T> empty() { |
Optional的方法
isPresent()
Optional的isPresent()方法用来判断是否包含值
1 | public boolean isPresent() { |
如果Optional中有值,则对该值调用consumer.accept,否则什么也不做
对于前面的getUserById例子,可以修改为:
1 | Optional<User> user = Optional.ofNullable(getUserById(id)); |
get()
get()用来获取Optional包含的值
注意:
如果值不存在,即在一个Optional.empty上调用get()方法的话,将会抛出NoSuchElementException异常
orElse()
1 | public T orElse(T other) { |
如果Optional中有值则将其返回,否则返回orElse方法传入的参数
1 | User user = Optional |
orElseGet
1 | public T orElseGet(Supplier<? extends T> other) { |
orElseGet与orElse方法的区别在于:orElseGet方法传入的参数为一个Supplier接口的实现
当Optional中有值的时候,返回值;当Optional中没有值的时候,返回从该Supplier获得的值
orElseThrow
1 | public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { |
orElseThrow与orElse方法的区别在于:orElseThrow方法当Optional中有值的时候,返回值;没有值的时候会抛出异常,抛出的异常由传入的exceptionSupplier提供
1 | User user = Optional |
orElseThrow示例
在SpringMVC的控制器中,我们可以配置统一处理各种异常.查询某个实体时,如果数据库中有对应的记录便返回该记录,否则就可以抛出EntityNotFoundException,处理EntityNotFoundException的方法中我们就给客户端返回Http状态码 404和异常对应的信息——orElseThrow完美的适用于这种场景
1 | "/{id}") ( |
其他方法
map
1 | public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { |
如果当前Optional为Optional.empty,则依旧返回Optional.empty;否则返回一个新的Optional,该Optional包含的是:函数mapper在以value作为输入时的输出值,例子如下:
1 | Optional<String> username = Optional |
多次map操作如下:
1 | Optional<String> username = Optional |
flatmap
1 | public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { |
flatMap方法与map方法的区别在于:map方法参数中的函数mapper输出的是值,然后map方法会使用Optional.ofNullable将其包装为Optional;而flatMap要求参数中的函数mapper输出的就是 Optional
具体示例如下:
1 | Optional<String> username = Optional |
filter
1 | public Optional<T> filter(Predicate<? super T> predicate) { |
filter方法接受一个Predicate来对Optional中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个Optional;否则返回Optional.empty
1 | Optional<String> username = Optional |
JDK9的增强
1.public Optional
2.public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) ifPresentOrElse方法的用途是:如果一个Optional包含值,则对其包含的值调用函数action,即action.accept(value),这与ifPresent一致;与ifPresent方法的区别在于:ifPresentOrElse还有第二个参数emptyAction——如果Optional不包含值,那么ifPresentOrElse便会调用emptyAction,即emptyAction.run()
3.public Stream
具体示例:
JDK8的写法:
1 | // 此处 getUserById 返回的是 Optional<User> |
JDK9的写法:
1 | public List<User> getUsers(Collection<Integer> userIds) { |