Java参数 之 严格求值

问题描述:.ge(StringUtils.isNotBlank(param.getCreateTimeStart()),CommonFileInfo::getCreatetime, dtf.parse(param.getCreateTimeStart())) 报空指针异常。
关键在于 Java 中方法参数的求值顺序


问题分析

你写的代码类似于 MyBatis-Plus 的条件构造器(如 QueryWrapper)中的链式调用:

.ge(
    StringUtils.isNotBlank(param.getCreateTimeStart()),
    CommonFileInfo::getCreatetime,
    dtf.parse(param.getCreateTimeStart())
)

你期望的是:

  • 如果 param.getCreateTimeStart()null 或空字符串,StringUtils.isNotBlank(...) 返回 false
  • 那么 .ge(false, ..., ...) 就不会添加该条件,同时 dtf.parse(...) 不会被执行

但实际情况是:在调用 .ge(...) 方法之前,Java 会先计算所有传入参数的值,包括第三个参数 dtf.parse(param.getCreateTimeStart())

所以即使第一个参数是 falsedtf.parse(param.getCreateTimeStart()) 依然会被执行。而 param.getCreateTimeStart()null,导致 dtf.parse(null) 抛出 NullPointerException(或 DateTimeParseException,取决于 dtf 类型)。

关键点:Java 是严格求值(eager evaluation)语言,方法的所有实参在方法调用前就已求值完成。


正确做法

你需要避免在参数中直接调用可能抛异常的方法,而是将解析逻辑放在条件判断内部。例如:

✅ 方案 1:提前判断并解析

String createTimeStart = param.getCreateTimeStart();
if (StringUtils.isNotBlank(createTimeStart)) {
    try {
        Date parsedDate = dtf.parse(createTimeStart);
        queryWrapper.ge(CommonFileInfo::getCreatetime, parsedDate);
    } catch (Exception e) {
        // 处理解析异常,如日志记录或抛出业务异常
        throw new IllegalArgumentException("创建时间格式错误", e);
    }
}

✅ 方案 2:使用三元运算符 + 安全解析(不推荐用于复杂逻辑)

如果 dtf.parse 可以安全处理 null(但通常不行),或者你封装一个安全方法:

Date safeParse(String str) {
    if (StringUtils.isBlank(str)) return null;
    try {
        return dtf.parse(str);
    } catch (Exception e) {
        return null; // 或抛异常
    }
}

// 使用时:
String start = param.getCreateTimeStart();
queryWrapper.ge(
    StringUtils.isNotBlank(start),
    CommonFileInfo::getCreatetime,
    safeParse(start)
);

但注意:即使这样,safeParse(start) 仍然会在 .ge() 调用前执行,只是它内部做了 null 判断。这可以避免异常,但逻辑上仍不如方案 1 清晰。


补充说明:MyBatis-Plus 的 .ge(condition, ...) 设计意图

MyBatis-Plus 的条件方法(如 .eq, .ge)确实支持 condition 参数来控制是否添加条件,但前提是其他参数必须是“可安全求值”的。它并不是“惰性求值”(lazy evaluation),不会因为 condition=false 就跳过其他参数的计算。

因此,不能把可能抛异常的表达式直接写在参数里


总结

  • ❌ 错误认知:认为 condition=false 时,后面的参数不会被计算。
  • ✅ 正确认知:所有参数在方法调用前都会被计算,无论 condition 值如何。
  • 🔧 解决方案:先判断字符串非空,再解析,最后调用 .ge()
posted @ 2026-01-16 14:43  蓝迷梦  阅读(1)  评论(0)    收藏  举报