专栏名称: 码小辫
给程序员和编程爱好者分享计算机编程电子书以及相关的学习资源
目录
相关文章推荐
51好读  ›  专栏  ›  码小辫

瞧瞧别人家的判空,那叫一个优雅!

码小辫  · 公众号  ·  · 2025-03-08 14:00

正文

一、传统判空的血泪史

某互联网金融平台因费用计算层级的空指针异常,导致凌晨产生9800笔错误交易。

DEBUG日志显示问题出现在如下代码段:

// 错误示例
BigDecimal amount = user.getWallet().getBalance().add(new BigDecimal("100"));

此类链式调用若中间环节出现null值,必定导致NPE。

初级阶段开发者通常写出多层嵌套式判断:

if(user != null){
    Wallet wallet = user.getWallet();
    if(wallet != null){
        BigDecimal balance = wallet.getBalance();
        if(balance != null){
            // 实际业务逻辑
        }
    }
}

这种写法既不优雅又影响代码可读性。

那么,我们该如何优化呢?

二、Java 8+时代的判空革命

Java8之后,新增了Optional类,它是用来专门判空的。

能够帮你写出更加优雅的代码。

1. Optional黄金三板斧

// 重构后的链式调用
BigDecimal result = Optional.ofNullable(user)
    .map(User::getWallet)
    .map(Wallet::getBalance)
    .map(balance -> balance.add(new BigDecimal("100")))
    .orElse(BigDecimal.ZERO);

高级用法:条件过滤

Optional.ofNullable(user)
    .filter(u -> u.getVipLevel() > 3)
    .ifPresent(u -> sendCoupon(u)); // VIP用户发券

2. Optional抛出业务异常

BigDecimal balance = Optional.ofNullable(user)
    .map(User::getWallet)
    .map(Wallet::getBalance)
    .orElseThrow(() -> new BusinessException("用户钱包数据异常"));

3. 封装通用工具类

public class NullSafe {
    
    // 安全获取对象属性
    publicstatic  get(T target, Function mapper, R defaultValue) {
        return target != null ? mapper.apply(target) : defaultValue;
    }
    
    // 链式安全操作
    publicstatic  execute(T root, Consumer consumer)  {
        if (root != null) {
            consumer.accept(root);
        }
        return root;
    }
}

// 使用示例
NullSafe.execute(user, u -> {
    u.getWallet().charge(new BigDecimal("50"));
    logger.info("用户{}已充值", u.getId());
});

三、现代化框架的判空银弹

4. Spring实战技巧

Spring中自带了一些好用的工具类,比如:CollectionUtils、StringUtils等,可以非常有效的进行判空。

具体代码如下:

// 集合判空工具
List orders = getPendingOrders();
if (CollectionUtils.isEmpty(orders)) {
    return Result.error("无待处理订单");
}

// 字符串检查
String input = request.getParam("token");
if (StringUtils.hasText(input)) {
    validateToken(input); 
}

5. Lombok保驾护航

我们在日常开发中的entity对象,一般会使用Lombok框架中的注解,来实现getter/setter方法。

其实,这个框架中也提供了@NonNull等判空的注解。

比如:

@Getter
@Setter
public class User {
    @NonNull // 编译时生成null检查代码
    private String name;
    
    private Wallet wallet;
}

// 使用构造时自动判空
User user = new User(@NonNull "张三", wallet);

四、工程级解决方案

6. 空对象模式

public interface Notification {
    void send(String message);
}

// 真实实现
publicclass EmailNotification implements Notification {
    @Override
    public void send(String message) {
        // 发送邮件逻辑
    }
}

// 空对象实现
publicclass NullNotification implements Notification {
    @Override
    public void send(String message) {
        // 默认处理
    }
}

// 使用示例
Notification notifier = getNotifier();
notifier.send("系统提醒"); // 无需判空

7. Guava的Optional增强

其实Guava工具包中,给我们提供了Optional增强的功能。

比如:

import com.google.common.base.Optional;

// 创建携带缺省值的Optional
Optional userOpt = Optional.fromNullable(user).or(defaultUser);

// 链式操作配合Function
Optional amount = userOpt.transform(u -> u.getWallet())
                                    .transform(w -> w.getBalance());

Guava工具包中的Optional类已经封装好了,我们可以直接使用。

五、防御式编程进阶

8. Assert断言式拦截







请到「今天看啥」查看全文