java8之optional
大约 3 分钟
主要用处:防止空指针(NPE)、简化if...else...判断、减少代码的复杂度
常用方法举例
empty()
1. 创建空的Optional:常见用法:业务不满足某条件时,返回空的Optional
public Optional<User> getManUser(Long userId) {
if (user.getSex() != Sex.MAN) {
// 如果性别是男,直接返回空
return Optional.empty();
}
}
of()
2. 创建非空的Optional:常见用法:组装一个非空的Optional便于后续业务处理
if (user.getAge() >= 18) {
// 如果成年了,则返回
return Optional.of(user);
}
}
ofNullable()
3. 创建需要判空的Optional:常见用法:从数据库或接口获取一个对象后,不知道是不是空,需要进行判断
public Optional<User> getUserFromUserCenter(Long userId) {
Optional<User> userOpt = Optional.ofNullable(userService.getUser(userId));
}
isPresent()
4. 判断Optional中对象是否是NULL:常见用法:判空后进行业务处理
if (userOpt.isPresent()) {
// 返回true,说明user不为NULL,则对其中的user对象进行处理
} else {
// 返回false,说明user为NULL
System.out.println("用户不存在");
}
ifPresent()
5. 非空表达式if:常见用法:代替if(xxx != null){},判断非空之后进行逻辑处理
// 接3中例子
// 如果user存在,则打印出名字
userOpt.ifPresent(user -> System.out.println(user.getName()));
ifPresentOrElse()
6. 非空表达式if else(JAVA9) :常见用法:代替if(xxx != null){} else {},对空和非空分别进行逻辑处理
// 如果user存在,则打印出名字, 否则提示不存在,相当于4中代码的改造
userOpt.ifPresentOrElse(user -> System.out.println(user.getName()), () -> System.out.println("用户不存在"));
orElse()
7. 设置默认值:常见用法:当对象为NULL时,需要指定一个默认值
// 如果user为NULL,则给new一个User
User user = Optional.ofNullable(user).orElse(new User());
orElseGet()
8. 设置默认值:常见用法:当对象为NULL时,需要指定一个默认值,与orElseGet()的区别是,如果Optional中对象不为Null,则不会执行orElseGet()中的方法
// 如果user为NULL,则从getDefaultUser中获取一个User
User user = Optional.ofNullable(user).orElseGet(UserUtil::getDefaultUser);
// 以下是orElse()和orElseGet()的对比
// 如果user为null,则两者都会执行UserUtil.getDefaultUser()方法
// 如果user不为null,则orElse会执行UserUtil.getDefaultUser()方法,orElseGet不会
// 所以某些情况下orElseGet性能更好
User user = Optional.ofNullable(user).orElse(UserUtil.getDefaultUser());
User user = Optional.ofNullable(user).orElseGet(UserUtil::getDefaultUser);
filter()
9. 过滤值:常见用法:需要对Optional中的对象进行过滤
// 判断user的年龄是否大于18岁
Optional<User> userOpt = Optional.ofNullable(user);
System.out.println(userOpt.filter(user -> user.getAge() >= 18).isPresent());
map()
10. 转换值:常见用法:将原始的Optional对象转换为新的Optional对象
// 将Optional<User>转换为Optional<Developer>
Optional<Developer> devOpt = Optional.ofNullable(user).map(user -> {
Developer dev = net Developer();
dev.setDevName(user.getName());
return dev;
});
实战改造
checkStyle
问题
1. 解决开发过程中经常会碰到这种问题,可以使用Optional简化
原代码:
BaseMasterSlaveServersConfig smssc = new BaseMasterSlaveServersConfig();
if (clientName != null) {
smssc.setClientName(clientName);
}
if (idleConnectionTimeout != null) {
smssc.setIdleConnectionTimeout(idleConnectionTimeout);
}
if (connectTimeout != null) {
smssc.setConnectTimeout(connectTimeout);
}
if (timeout != null) {
smssc.setTimeout(timeout);
}
if (retryAttempts != null) {
smssc.setRetryAttempts(retryAttempts);
}
if (retryInterval != null) {
smssc.setRetryInterval(retryInterval);
}
if (reconnectionTimeout != null) {
smssc.setReconnectionTimeout(reconnectionTimeout);
}
if (password != null) {
smssc.setPassword(password);
}
if (failedAttempts != null) {
smssc.setFailedAttempts(failedAttempts);
}
// ...后面还有很多这种判断,一个if就是一个分支,会增长圈复杂度
改造后:
Optional.ofNullable(clientName).ifPresent(smssc::setClientName);
Optional.ofNullable(idleConnectionTimeout).ifPresent(smssc::setIdleConnectionTimeout);
Optional.ofNullable(connectTimeout).ifPresent(smssc::setConnectTimeout);
Optional.ofNullable(timeout).ifPresent(smssc::setTimeout);
Optional.ofNullable(retryAttempts).ifPresent(smssc::setRetryAttempts);
Optional.ofNullable(retryInterval).ifPresent(smssc::setRetryInterval);
Optional.ofNullable(reconnectionTimeout).ifPresent(smssc::setReconnectionTimeout);
// ...缩减为一行,不但减少了圈复杂度,而且减少了行数
2. 简化if...else
原代码:
// 获取用户,找不到则新增,找到则改变用户状态
User user = userDao.getUserById(userId);
if (user == null) {
User user = new User();
user.setName("用户");
userDao.save(user);
} else {
user.setStatus(1);
userDao.update(user);
}
改造后:
// 把新增用户和更新用户的方法提出来,可读性更高
Optional.ofNullable(userDao.getUserById(userId)).ifPresentOrElse(user -> saveUser(), user -> updateUser(user));
// 保存用户
private void saveUser(){
User user = new User();
user.setName("用户");
userDao.save(user);
}
// 更新用户
private void updateUser(User user){
user.setStatus(1);
userDao.update(user);
}