跳至主要內容

java8之optional

知识库编程技巧JavaJava大约 3 分钟

主要用处:防止空指针(NPE)、简化if...else...判断、减少代码的复杂度

常用方法举例

1. 创建空的Optional:empty()

常见用法:业务不满足某条件时,返回空的Optional

public Optional<User> getManUser(Long userId) {
    if (user.getSex() != Sex.MAN) {
        // 如果性别是男,直接返回空
        return Optional.empty();
    }
}

2. 创建非空的Optional:of()

常见用法:组装一个非空的Optional便于后续业务处理

    if (user.getAge() >= 18) {
        // 如果成年了,则返回
        return Optional.of(user);
    }
}

3. 创建需要判空的Optional:ofNullable()

常见用法:从数据库或接口获取一个对象后,不知道是不是空,需要进行判断

public Optional<User> getUserFromUserCenter(Long userId) {
    Optional<User> userOpt = Optional.ofNullable(userService.getUser(userId));
}

4. 判断Optional中对象是否是NULL:isPresent()

常见用法:判空后进行业务处理

if (userOpt.isPresent()) {
    // 返回true,说明user不为NULL,则对其中的user对象进行处理
} else {
    // 返回false,说明user为NULL
    System.out.println("用户不存在");
}

5. 非空表达式if:ifPresent()

常见用法:代替if(xxx != null){},判断非空之后进行逻辑处理

// 接3中例子
// 如果user存在,则打印出名字
userOpt.ifPresent(user -> System.out.println(user.getName()));

6. 非空表达式if else(JAVA9) :ifPresentOrElse()

常见用法:代替if(xxx != null){} else {},对空和非空分别进行逻辑处理

// 如果user存在,则打印出名字, 否则提示不存在,相当于4中代码的改造
userOpt.ifPresentOrElse(user -> System.out.println(user.getName()), () -> System.out.println("用户不存在"));

7. 设置默认值:orElse()

常见用法:当对象为NULL时,需要指定一个默认值

// 如果user为NULL,则给new一个User
User user = Optional.ofNullable(user).orElse(new User());

8. 设置默认值:orElseGet()

常见用法:当对象为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);

9. 过滤值:filter()

常见用法:需要对Optional中的对象进行过滤

// 判断user的年龄是否大于18岁
Optional<User> userOpt = Optional.ofNullable(user);
System.out.println(userOpt.filter(user -> user.getAge() >= 18).isPresent());

10. 转换值:map()

常见用法:将原始的Optional对象转换为新的Optional对象

// 将Optional<User>转换为Optional<Developer>
Optional<Developer> devOpt = Optional.ofNullable(user).map(user -> {
    Developer dev = net Developer();
    dev.setDevName(user.getName());
    return dev;
});

实战改造

1. 解决checkStyle问题

开发过程中经常会碰到这种问题,可以使用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);
}