聊一聊Java8 Optional,让你的代码更加优雅
码农在囧途
随着时间的推移,曾经我们觉得重要的东西,可能在今天看来是如此的浅薄和无知,同理,今天我们放不下,想不开,觉得重要的东西,多年后我们可能也会觉得也就那样,所以,今天的的所有烦恼,忧愁,想不开,其实我们都没必要过于在意,因为有些东西随着时间的冲刷,也就那样了。
前言
Java8提供了Optional接口,Optional接口能够是我们的代码变得更加的优雅,可读性更高,同时能够很好的避免空指针,因为空指针是一个很让人头疼的问题,特别对于调用第三方接口,如果不知道对象的规约的时候,我们在取值的时候无法直到那些值能为空,那些不能为空,所以容易出现空指针,如果我们谨慎一点,可能会对每一个值进行判空处理,但是将会充斥着大量的if语句,甚是不雅观。
下面我们介绍一下Optional类的方法
empty()
返回一个空的Optional对象 Optional.empty
of(T value)
参数传入一个对象,返回一个Option对象,value不能为空,如果为null,将抛出空指针异常
/**
* @author 刘牌
* @date 2022-03-2921:52
*/
public class OptionalTest {
public static void main(String[] args) {
User user = null;
Optional<User> optional = Optional.of(user);
System.out.println(user);
}
}
ofNullable(T value)
参数传入一个对象,可以为空,如果为空,将返回一个空的Optional对象,就等于Optional.empty(),输出的值为Optional.empty,如果不为空,返回一个不为空的Optional对象
/**
* @author 刘牌
* @date 2022-03-2921:52
*/
public class OptionalTest {
public static void main(String[] args) {
User user = null;
Optional<User> optional = Optional.ofNullable(user);
System.out.println(optional);
}
}
get()
获取Optional中的值,这个值也就是我们的值,Optional相当于就是一个外壳。
public class OptionalTest {
public static void main(String[] args) {
User user = null;
Optional<User> optional = Optional.ofNullable(user);
User user1 = optional.get();
}
}
isPresent()
判断Optional对象中是否有值,如果有值,返回true,没值返回false。
true
public class OptionalTest {
public static void main(String[] args) {
User user = new User();
Optional<User> optional = Optional.ofNullable(user);
System.out.println(optional.isPresent());
}
}
false
public class OptionalTest {
public static void main(String[] args) {
User user = null;
Optional<User> optional = Optional.ofNullable(user);
System.out.println(optional.isPresent());
}
}
ifPresent(Consumer<? super T> consumer)
ifPresent参数是一个函数式接口,无返回值,会将Optional中的值作为参数传递到ifPresent()中
public class OptionalTest {
public static void main(String[] args) {
User user = new User();
Optional<User> optional = Optional.ofNullable(user);
optional.ifPresent(s -> System.out.println(s));
}
}
filter(Predicate<? super T> predicate)
是一个Predicate函数接口,会将Optional中的值作为参数传入,如果符合规则,那么返回一个Optional对象,否则返回一个空的Optional 对象(Optional.empty) 符合规则,返回Optional对象
public class OptionalTest {
public static void main(String[] args) {
User user = new User();
user.setUsername("我是小四哥");
Optional<User> optional = Optional.ofNullable(user);
Optional<User> optional1 = optional.filter(v -> v.getUsername().equals("我是小四哥"));
System.out.println(optional1);
}
}
不符合规则,返回空Optional(Optional.empty)
public class OptionalTest {
public static void main(String[] args) {
User user = new User();
user.setUsername("我是小四哥");
Optional<User> optional = Optional.ofNullable(user);
Optional<User> optional1 = optional.filter(v -> v.getUsername().equals("我不是小四哥"));
System.out.println(optional1);
}
}
map(Function<? super T, ? extends U> mapper)
参数是一个Function函数式接口,会将Optional中的值作为参数传递到map中,如果传入的值为空,则返回一空的Optional对象,相当于Optional.empty(), 如果不为空,我们可以返回一个可以描述描述结果的返回值(Optional中的值,这个值可以重新赋值),如下面的返回一个tempUser
Optional中的值为空
public class OptionalTest {
public static void main(String[] args) {
User user = null;
Optional<String> optional = Optional.ofNullable(user).map(OptionalTest::getMap);
System.out.println(optional); //Optional.empty
}
public static String getMap(User user){
return user.getUsername();
}
}
Optional中的值不为空
public class OptionalTest {
public static void main(String[] args) {
User user = new User();
user.setUsername("我是小四哥");
user.setAge(20);
Optional<String> optional = Optional.ofNullable(user).map(OptionalTest::getMap);
System.out.println(optional); // Optional[我是小四哥]
}
public static String getMap(User user){
return user.getUsername();
}
}
flatMap(Function<? super T, Optional> mapper)
如果Optional中值存在,那么返回一个基于Optional的值(如Optional),如果Optional中的值不存在,则返回一空的Optional对象,相当于Optional.empty(),与map不同, map返回的是一个值,而flatMap返回一个基于Optional的值
public class OptionalTest {
public static void main(String[] args) {
User user = new User();
user.setUsername("我是小四哥");
user.setAge(20);
Optional<String> optional = Optional.ofNullable(user).flatMap(OptionalTest::getFlatMap);
System.out.println(optional);
}
public static Optional<String> getFlatMap(User user){
return Optional.ofNullable(user).map(User::getUsername);
}
}
orElse(T other)
如果Optional中的值不为空,则返回Optional中的值,如果为空,则返回other值,
String value = "2";
String orElse = Optional.ofNullable(value).orElse("1");
System.out.println(orElse); //2
String value = null;
String orElse = Optional.ofNullable(value).orElse("1");
System.out.println(orElse); //1
orElseGet(Supplier<? extends T> other)
如果Optional中存在值,则返回值,否则返回other调用的结果
Optional中存在值
public class OptionalTest {
public static void main(String[] args) {
String value = null;
String orElse = Optional.ofNullable(value).orElseGet(OptionalTest::get);
System.out.println(orElse); // 123
}
public static String get(){
return "123";
}
}
Optional中不存在值
public class OptionalTest {
public static void main(String[] args) {
String value = "2";
String orElse = Optional.ofNullable(value).orElseGet(OptionalTest::get);
System.out.println(orElse); // 2
}
public static String get(){
return "123";
}
}
orElseThrow(Supplier<? extends X> exceptionSupplier)
如果Optional中的值存在,则返回值,值不存在,则抛出异常函数Supplier中的异常
public class OptionalTest {
public static void main(String[] args) {
String value = null;
String orElse = Optional.ofNullable(value).orElseThrow(() -> new RuntimeException("不存在值"));
System.out.println(orElse);
}
}
输出
Exception in thread "main" java.lang.RuntimeException: 不存在值
at com.steak.javase.optional.OptionalTest.lambda$main$0(OptionalTest.java:14)
at java.util.Optional.orElseThrow(Optional.java:290)
at com.steak.javase.optional.OptionalTest.main(OptionalTest.java:13)
实战,去除if判断
我们将一个从远程接口获取了一个用户的信息,包含家庭信息,学历信息,个人信息,然后封装成一个VO,再返回前端进行展示。
家庭实体Family
/**
* @author 刘牌
* @date 2022-03-3023:22
*/
@Data
@Accessors(chain = true)
public class Family {
private String fatherName;
private String motherName;
}
学历实体Education
@Data
@Accessors(chain = true)
public class Education {
private String education;
private String schoolName;
private Date admissionTime;
private Date graduationTime;
}
用户信息实体UserInfo
/**
* @author 刘牌
* @date 2022-03-3023:16
*/
@Data
@Accessors(chain = true)
public class UserInfo {
private String name;
private Integer age;
private Family family;
private Education education;
}
用户VO,返回前端的视图对象
/**
* @author 刘牌
* @date 2022-03-2922:02
*/
@Data
@Accessors(chain = true)
public class UserVO {
private String username;
private Integer userAge;
private String edu;
private String school;
private Date admissionDate;
private Date graduationDate;
private String mother;
private String father;
}
如果没有做判空处理,如下代码,因为getUser()接口中并没有为family属性设值,所以为null,那么main方法中对其进行赋值的时候,肯定会抛出空指针异常NullPointerException。
/**
* @author 刘牌
* @date 2022-03-2921:52
*/
public class OptionalTest {
public static void main(String[] args) {
UserInfo userInfo = getUser();
UserVO user = new UserVO();
user.setUsername(userInfo.getName()).setUserAge(userInfo.getAge())
.setEdu(userInfo.getEducation().getEducation())
.setSchool(userInfo.getEducation().getSchoolName())
.setAdmissionDate(userInfo.getEducation().getAdmissionTime())
.setGraduationDate(userInfo.getEducation().getGraduationTime())
.setFather(userInfo.getFamily().getFatherName())
.setMother(userInfo.getFamily().getMotherName());
System.out.println(user);
}
public static UserInfo getUser(){
Family family = new Family().setFatherName("father")
.setMotherName("mother");
Education education = new Education().setEducation("本科")
.setSchoolName("家里蹲大学")
.setAdmissionTime(new Date())
.setGraduationTime(new Date());
return new UserInfo()
.setName("小四哥")
.setAge(24)
.setEducation(education);
}
}
所以我们需要做判空校验,那么大多数人肯定会使用如下方式进行判断,先判断userInfo是否null,再接着判断education属性和family属性是否为null,为null不赋值,这样就能避免空指针,这是绝大多数人都会这样做的,这样做确实是没错的,但是我们发现代码中存在很多if判空操作,看起来其实不怎么好看。
if (null != userInfo){
user.setUsername(userInfo.getName()).setUserAge(userInfo.getAge());
if (null != userInfo.getEducation()){
user.setEdu(userInfo.getEducation().getEducation())
.setSchool(userInfo.getEducation().getSchoolName())
.setAdmissionDate(userInfo.getEducation().getAdmissionTime())
.setGraduationDate(userInfo.getEducation().getGraduationTime());
}
if (null != userInfo.getFamily()){
user.setFather(userInfo.getFamily().getFatherName())
.setMother(userInfo.getFamily().getMotherName());
}
}
使用Optional接口进行改造,额~~~,这好像也没改造出啥东西来啊,没错,确实没改造出什么新花样来,除了增加一些函数操作,基本没啥改变,但是我们能直观的看出,代码比上面的会好维护一点,因为大家都比较烦if,那么,除了好看一点,好维护一点,还有啥好处呢,我觉得如果你对一些返回的结果不能很确定其返回值值的情况下,那么使用Optional来避免空指针是一个很好的办法,因为在开发中可能并不会想得那么周到,可能某处因为疏忽或者没考虑到,忘记加了if判空,那么后续可能会导致空指针,如果使用Optional的话,那么这个问题能够得到避免。
Optional.ofNullable(userInfo).ifPresent(userInfoI -> {
user.setUsername(userInfoI.getName()).setUserAge(userInfoI.getAge());
Optional.ofNullable(userInfoI.getFamily()).ifPresent(family -> {
user.setFather(userInfo.getFamily().getFatherName()).setMother(userInfo.getFamily().getMotherName());
});
Optional.ofNullable(userInfoI.getEducation()).ifPresent(education -> {
user.setEdu(userInfo.getEducation().getEducation())
.setSchool(userInfo.getEducation().getSchoolName())
.setAdmissionDate(userInfo.getEducation().getAdmissionTime())
.setGraduationDate(userInfo.getEducation().getGraduationTime());
});
});
获取用户毕业时间,去除if多重判断
不使用Optional,使用if判断
public static Date getGraduationTime(UserInfo userInfo){
if (null != userInfo){
if (null != userInfo.getEducation()){
return userInfo.getEducation().getGraduationTime();
}
}
return null;
}
使用Optional
public static Date getGraduationTime(UserInfo userInfo){
return Optional.ofNullable(userInfo)
.map(UserInfo::getEducation)
.map(Education::getGraduationTime)
.orElse(null);
}
关于Optional,里面还有很多好用的方法和操作,我们就不展开了。
今天的分享就到这里,感谢你的观看,我们下期见!
聊一聊Java8 Optional,让你的代码更加优雅的更多相关文章
- java代码之美(16) ---Java8 Optional
Java8 Optional 一句话介绍Optional类:使用JDK8的Optional类来防止NullPointerException(空指针异常)问题. 一.前言 在我们开放过程中,碰到的异常中 ...
- Java8 Optional的简单操作
我们经常会遇到这种情况:首先判断一个对象是否为null,如果不为null,获取一个对象中的一个属性,如果该属性不为null,又获取该属性的属性,如果该属性的属性不为null,又获取属性的属性的属性: ...
- java8 Optional优雅非空判断
java8 Optional优雅非空判断 import java.util.ArrayList;import java.util.List;import java.util.Optional; pub ...
- Java8 Optional && Guava Optional
Java8 -- Optional boolean isPresent():与obj != null()一样:调用get()前要调用isPresent()检查,不然会报错 Optional的三种构造方 ...
- JDK8漫谈——代码更优雅
简介 lambda表达式,又称闭包(Closure)或称匿名方法(anonymous method).将Lambda表达式引入JAVA中的动机源于一个叫"行为参数"的模式.这种模式 ...
- JAVA8-让代码更优雅之List排序
先定义一个实体类 @Data @AllArgsConstructor @NoArgsConstructor public class Human { private String name; priv ...
- 用Assert(断言)封装异常,让代码更优雅(附项目源码)
有关Assert断言大家并不陌生,我们在做单元测试的时候,看业务事务复合预期,我们可以通过断言来校验,断言常用的方法如下: public class Assert { /** * 结果 = 预期 则正 ...
- Lambda表达式, 可以让我们的代码更优雅.
在C#中, 适当地使用Lambda表达式, 可以让我们的代码更优雅. 通过lambda表达式, 我们可以很方便地创建一个delegate: 下面两个语句是等价的 Code highlighting p ...
- CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅
首页 登录注册 CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅 阅读 8113 收藏 927 2017-09-26 原文链接:github.com 腾讯云容器服务CSS,立 ...
随机推荐
- bool? int?等可为空的数值类型的运算 三值逻辑
算术运算:(+,-,*,/)时,只要一个为null,则结果为null. 比较运算符: <.>.<= 和 >=,也是如此.如果一个或全部两个操作数都为 null,则结果为 fal ...
- Oracle之查询排序
SQL排序查询 DESC降序.ASC升序(默认是升序) /* 语法结构: SELECT * | 列名1[,列名2...] | 表达式 FROM 表名 [WHERE 限定条件] ORDER BY 列名1 ...
- P4-可编程语言代码学习
(1).behavioral-model 简称bmv2 P4程序首先经过p4c-bm模块编译成JSON格式的配置文件,然后将配置文件载入到bmv2中,转化成能实现交换机功能的数据结构. behavio ...
- LeetCode-082-删除排序链表中的重复元素 II
删除排序链表中的重复元素 II 题目描述:存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字. 返回同样按升序 ...
- 使用Three.js实现神奇的3D文字悬浮效果
声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 在 Three.js Journey 课程示例中,提供了一个使用 Thre ...
- php 23种设计模型 - 中介者模式
中介者模式 中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性.这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护.中介者模式属于行 ...
- centos7下mysql安装
centos7只包含了mariadb的安装源 我们需要到官方下载社区版:https://dev.mysql.com/downloads/ 下载安装包并上传到服务器 安装出现错误 这个是系统自带的Mar ...
- springboot Redistemplate的execute和 executePipelined
springboot 的 RedisTemplate 的 execute 和 executePipelined 功能的区别 1.execute 以下是 springboot 官网原文: Redis p ...
- UOJ188题解
我们先枚举一个最大质因子,然后设 \(dp[n][k]\) 为 \(n\) 以内使用了 \(pri[k]\) 以内的质数的数的最大质因子之和,答案就是: \[\sum_{k\leq n}dp[\lfl ...
- SP3734题解
题意: 有 \(n\) 列表格,第 \(i\) 列有 \(a_i\) 个格子,问在 \(n\) 列表格中有多少种放置 \(k\) 个棋子的方法使没有棋子在同一列和同一行.(如果中间有一个"格 ...