}
但是很多时候,我们可能会忘记写 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()
方法会返回该对象。
JDK
提供三个静态方法来构造一个 Optional
:
1.Optional.of(T value)
,该方法通过一个非 null
的 value
来构造一个 Optional
,返回的 Optional
包含了value
这个值。对于该方法,传入的参数一定不能为 null
,否则便会抛出 NullPointerException
。
2.Optional.ofNullable(T value)
,该方法和 of
方法的区别在于,传入的参数可以为 null
—— 但是前面 javadoc
不是说Optional
只能包含非 null
值吗?我们可以看看 ofNullable
方法的源码:
原来该方法会判断传入的参数是否为 null
,如果为 null
的话,返回的就是 Optional.empty()
。
3.Optional.empty()
,该方法用来构造一个空的 Optional
,即该 Optional
中不包含值 —— 其实底层实现还是 如果 Optional
中的 value
为 null
则该 Optional
为不包含值的状态,然后在 API
层面将 Optional
表现的不能包含 null
值,使得 Optional
只存在 包含值 和 不包含值 两种状态。
前面 javadoc
也有提到,Optional
的 isPresent()
方法用来判断是否包含值,get()
用来获取 Optional
包含的值 —— 值得注意的是,如果值不存在,即在一个Optional.empty
上调用 get()
方法的话,将会抛出 NoSuchElementException
异常。
我们假设 getUserById
已经是个客观存在的不能改变的方法,那么利用 isPresent
和 get
两个方法,我们现在能写出下面的代码:
Optional user = Optional.ofNullable(getUserById(id));
if (user.isPresent()) {
String username = user.get().getUsername();
System.out.println("Username is: " + username); // 使用 username
}
好像看着代码是优美了点 —— 但是事实上这与之前判断 null
值的代码没有本质的区别,反而用 Optional
去封装 value
,增加了代码量。所以我们来看看 Optional
还提供了哪些方法,让我们更好的(以正确的姿势)使用 Optional
。
1.1 ifPresent
如果 Optional
中有值,则对该值调用 consumer.accept
,否则什么也不做。
所以对于上面的例子,我们可以修改为:
Optional user = Optional.ofNullable(getUserById(id));
user.ifPresent(u -> System.out.println("Username is: " + u.getUsername()));
1.2 orElse
如果 Optional
中有值则将其返回,否则返回 orElse
方法传入的参数。
User user = Optional
.ofNullable(getUserById(id))
.orElse(new User(0, “Unknown”));
System.out.println("Username is: " + user.getUsername());
1.3 orElseGet
orElseGet
与 orElse
方法的区别在于,orElseGet
方法传入的参数为一个 Supplier
接口的实现 —— 当 Optional
中有值的时候,返回值;当 Optional
中没有值的时候,返回从该 Supplier
获得的值。
User user = Optional
.ofNullable(getUserById(id))
.orElseGet(() -> new User(0, “Unknown”));
System.out.println("Username is: " + user.getUsername());
1.4 orElseThrow
orElseThrow
与 orElse
方法的区别在于,orElseThrow
方法当 Optional
中有值的时候,返回值;没有值的时候会抛出异常,抛出的异常由传入的 exceptionSupplier
提供。
User user = Optional
.ofNullable(getUserById(id))
.orElseThrow(() -> new EntityNotFoundException(“id 为 " + id + " 的用户没有找到”));
举一个 orElseThrow
的用途:在 SpringMVC
的控制器中,我们可以配置统一处理各种异常。查询某个实体时,如果数据库中有对应的记录便返回该记录,否则就可以抛出 EntityNotFoundException
,处理 EntityNotFoundException
的方法中我们就给客户端返回Http
状态码404
和异常对应的信息 —— orElseThrow
完美的适用于这种场景。
@RequestMapping(“/{id}”)
public User getUser(@PathVariable Integer id) {
Optional user = userService.getUserById(id);
return user.orElseThrow(() -> new EntityNotFoundException(“id 为 " + id + " 的用户不存在”));
}
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity handleException(EntityNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
1.5 map
如果当前 Optional
为 Optional.empty
,则依旧返回Optional.empty
;否则返回一个新的 Optional
,该 Optional
包含的是:函数 mapper
在以value
作为输入时的输出值。
String username = Optional.ofNullable(getUserById(id))
.map(user -> user.getUsername())
.orElse(“Unknown”)
.ifPresent(name -> System.out.println("Username is: " + name));
而且我们可以多次使用 map
操作:
Optional username = Optional.ofNullable(getUserById(id))
.map(user -> user.getUsername())
.map(name -> name.toLowerCase())
.map(name -> name.replace(‘_’, ’ '))
.orElse(“Unknown”)
.ifPresent(name -> System.out.println("Username is: " + name));
1.6 flatMap
flatMap
方法与map
方法的区别在于,map
方法参数中的函数 mapper
输出的是值,然后 map
方法会使用 Optional.ofNullable
将其包装为Optional
;而 flatMap
要求参数中的函数mapper
输出的就是 Optional
。
Optional username = Optional.ofNullable(getUserById(id))
.flatMap(user -> Optional.of(user.getUsername()))
.flatMap(name -> Optional.of(name.toLowerCase()))
.orElse(“Unknown”)
.ifPresent(name -> System.out.println("Username is: " + name));
1.7 filter
filter
方法接受一个 Predicate
来对 Optional
中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个 Optional
;否则返回 Optional.empty
。
Optional username = Optional.ofNullable(getUserById(id))
.filter(user -> user.getId() < 10)
.map(user -> user.getUsername());
.orElse(“Unknown”)
.ifPresent(name -> System.out.println("Username is: " + name));
有了 Optional
,我们便可以方便且优雅的在自己的代码中处理 null
值,而不再需要一昧通过容易忘记和麻烦的 if (object != null)
来判断值不为 null
。如果你的程序还在使用 Java8
之前的 JDK
,可以考虑引入Google
的 Guava
库 —— 事实上,早在 Java6
的年代,Guava
就提供了 Optional
的实现。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
总结
上述知识点,囊括了目前互联网企业的主流应用技术以及能让你成为“香饽饽”的高级架构知识,每个笔记里面几乎都带有实战内容。
很多人担心学了容易忘,这里教你一个方法,那就是重复学习。
打个比方,假如你正在学习 spring 注解,突然发现了一个注解@Aspect,不知道干什么用的,你可能会去查看源码或者通过博客学习,花了半小时终于弄懂了,下次又看到@Aspect 了,你有点郁闷了,上次好像在哪哪哪学习,你快速打开网页花了五分钟又学会了。
从半小时和五分钟的对比中可以发现多学一次就离真正掌握知识又近了一步。
人的本性就是容易遗忘,只有不断加深印象、重复学习才能真正掌握,所以很多书我都是推荐大家多看几遍。哪有那么多天才,他只是比你多看了几遍书。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
习 spring 注解,突然发现了一个注解@Aspect,不知道干什么用的,你可能会去查看源码或者通过博客学习,花了半小时终于弄懂了,下次又看到@Aspect 了,你有点郁闷了,上次好像在哪哪哪学习,你快速打开网页花了五分钟又学会了。
从半小时和五分钟的对比中可以发现多学一次就离真正掌握知识又近了一步。
[外链图片转存中…(img-l9oJ4OSz-1713398246475)]
人的本性就是容易遗忘,只有不断加深印象、重复学习才能真正掌握,所以很多书我都是推荐大家多看几遍。哪有那么多天才,他只是比你多看了几遍书。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!