You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决SpringBoot Kotlin项目使用?仍出现空指针异常的问题

问题根因
  • 强制解包运算符!!滥用:你虽然给DTO字段加了可空标识?,但在代码多处使用!!强行解包可空变量,只要变量为null就会直接抛出空指针,完全失去了空安全的防护效果。
  • DTO初始化逻辑风险:ReqMaterialReturn类中pending:Long? = totalPiecesMaterial- deposit!!这里直接对deposit强制解包,只要deposit为null,DTO实例化阶段就会抛出空指针。
  • 参数绑定问题:Controller使用@ModelAttribute接收表单/查询参数,如果前端未传递withdrawId、userId、deposit这类必填参数,或者传了空值,会直接覆盖你设置的默认值-1,导致变量实际为null。
  • 数据库查询结果为空风险:findByWithdrawId返回值是可空的Long?,如果传入的withdrawId在数据库中没有对应记录,查询结果为null,你用!!强制解包也会触发空指针。
修复方案

1. 修正DTO的安全初始化

把强制解包替换为空安全调用,避免DTO实例化阶段就抛出异常:

data class ReqMaterialReturn(
    val userId:Long?=-1,
    val withdrawId:Long?=-1,
    val deposit:Long?=-1,
    val totalPiecesMaterial:Long=-1,
    // 替换deposit!!为安全调用,deposit为null时pending也返回null
    val pending:Long? = deposit?.let { totalPiecesMaterial - it },
    val workStatus:Boolean?=false,
    val workPrice : Double?= deposit?.times(3.5),
    val depositedAt: LocalDateTime? = LocalDateTime.now()
)

2. 新增必填参数校验,避免空值流入业务逻辑

在Service处理前先校验必填参数是否为空,为空直接抛出业务异常或者返回错误提示,禁止用!!强行解包:

fun acceptMaterial(request:ReqMaterialReturn):MaterialReturn {
    // 先校验必填参数
    val userId = request.userId ?: throw IllegalArgumentException("userId不能为空")
    val withdrawId = request.withdrawId ?: throw IllegalArgumentException("withdrawId不能为空")
    val deposit = request.deposit ?: throw IllegalArgumentException("deposit不能为空")
    // 校验查询结果不为空
    val totalPieces = materialReturnRepository.findByWithdrawId(withdrawId) 
        ?: throw IllegalArgumentException("对应withdrawId的领料记录不存在")
    val depositMaterial = MaterialReturn(
        userId = userId,
        withdrawId = withdrawId,
        deposit = deposit,
        totalPiecesMaterial = totalPieces
    )
    return materialReturnRepository.save(depositMaterial)
}

同时可以把Repository方法的入参改为非空,避免空值传入查询:

@Query("select m.pieces from WithdrawMaterial  as m where m.withdrawId =:withdrawId")
fun findByWithdrawId(@RequestParam("withdrawId") withdrawId: Long): Long?

3. 优化Controller参数接收

如果你的接口是接收JSON参数,建议把@ModelAttribute换成@RequestBody,参数绑定更稳定,同时可以配合JSR380校验注解做参数自动校验:
首先给DTO加校验注解:

import jakarta.validation.constraints.NotNull
data class ReqMaterialReturn(
    @field:NotNull(message = "userId不能为空")
    val userId:Long?=-1,
    @field:NotNull(message = "withdrawId不能为空")
    val withdrawId:Long?=-1,
    @field:NotNull(message = "deposit不能为空")
    val deposit:Long?=-1,
    // 其余字段保持不变
)

然后Controller修改参数注解,加@Valid开启自动校验:

@PostMapping("/deposit")
fun depositMaterial(@RequestBody @Valid request:ReqMaterialReturn):ResponseEntity<*>{
    // 原有逻辑保持不变
}

参数为空时框架会自动返回参数错误提示,无需手动编写基础校验逻辑。

内容的提问来源于stack exchange,提问作者Mama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 16:54:05