03_Mybatis-Plus LambadaQueryWrapper 表达式爆空指针异常
🌟 03_MyBatis-Plus LambdaQueryWrapper
爆出空指针异常的坑点分析
❓ 场景描述
来看一段常见的 MyBatis-Plus 查询写法,是否存在问题?
Page<VideoInfoVo> videoInfoVosPage = videoMapper.selectPage(page, new LambdaQueryWrapper<VideoInfoVo>().eq(videoAdtReq.getUserId() != null, VideoInfoVo::getUserId, videoAdtReq.getUserId()).ge(videoAdtReq.getStartTime() != null, VideoInfoVo::getUpdateTime, videoAdtReq.getStartTime().atStartOfDay()).le(videoAdtReq.getEndTime() != null, VideoInfoVo::getUpdateTime, videoAdtReq.getEndTime().atTime(LocalTime.MAX))
);
💥 问题分析:会爆出 NullPointerException!
🔍 错误点在哪?
.ge(videoAdtReq.getStartTime() != null, VideoInfoVo::getUpdateTime, videoAdtReq.getStartTime().atStartOfDay())
.le(videoAdtReq.getEndTime() != null, VideoInfoVo::getUpdateTime, videoAdtReq.getEndTime().atTime(LocalTime.MAX))
表面上看已经做了非空判断,似乎没有问题,但实际上,这样写仍然可能爆出 NullPointerException
。
🚨 关键误区:Java 的参数求值顺序
Java 会在调用方法前,先对所有参数进行求值,然后再把这些值传给方法体。
所以即使你写了:
videoAdtReq.getStartTime() != null
Java 仍然会执行:
videoAdtReq.getStartTime().atStartOfDay()
如果 getStartTime()
返回的是 null
,那 .atStartOfDay()
立即爆 NPE
!
✅ 正确写法:提前提取变量,避免链式空指针
LocalDateTime start = null;
LocalDateTime end = null;if (videoAdtReq.getStartTime() != null) {start = videoAdtReq.getStartTime().atStartOfDay();
}
if (videoAdtReq.getEndTime() != null) {end = videoAdtReq.getEndTime().atTime(LocalTime.MAX);
}Page<VideoInfoVo> videoInfoVosPage = videoMapper.selectPage(page, new LambdaQueryWrapper<VideoInfoVo>().eq(videoAdtReq.getUserId() != null, VideoInfoVo::getUserId, videoAdtReq.getUserId()).ge(start != null, VideoInfoVo::getUpdateTime, start).le(end != null, VideoInfoVo::getUpdateTime, end)
);
🧠 小结 Tips
写法 | 是否安全 | 原因 |
---|---|---|
.eq(cond, field, value) | ✅ 安全 | 不涉及链式 null 调用 |
.ge(cond, field, value.atStartOfDay()) | ❌ 危险 | 即使 cond == false ,value.atStartOfDay() 已执行 |
📌 建议
- 所有可能为
null
的链式操作都要提前拆解; - 不要在
.ge()
、.le()
、.like()
等条件方法内部写链式 null 调用; - 最好在写查询条件前,先准备好转换后的数据变量。