基本数据类型默认值(如int为0、boolean为false)易被误作有效业务值,掩盖“未赋值”状态,引发权限绕过等风险;应改用包装类、显式初始化、判空校验及反序列化严格模式加以规避。

基本数据类型本身不会引发空指针异常,但它们的默认值(如 int 为 0、boolean 为 false)在业务中常被误当作“有效语义”,从而掩盖真实缺失状态,导致权限绕过、统计偏差、逻辑误判等风险。规避关键不在消灭默认值,而在于让“未赋值”和“明确取值”在代码里可区分、可感知、可校验。
用包装类替代基本类型表达“可选”语义
当字段业务上允许“未提供”(比如用户未填年龄、订单未设优先级),就别用 int age,改用 Integer age。这样反序列化或构造时若该字段缺失,值就是 null,而不是悄悄变成 0。
配合显式检查:
• 接口入参校验:Objects.requireNonNull(age, "age must be provided")
• 条件判断前先判空:if (age != null && age > 18) { ... }
• JSON 反序列化时开启严格模式(如 Jackson 的 DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
给成员变量加显式初始化,赋予业务含义
不依赖 JVM 自动填 0 或 false,而是主动写明初始意图:
• 数值型:用 -1 表示“无效”、Integer.MIN_VALUE 表示“未计算”
• 布尔型:避免直接声明 boolean isActive,改用 Boolean isActive 或增加状态标记字段 boolean isActiveSet = false
• 字符串/集合:初始化为 "" 或 new ArrayList(),而非留空或 null,既防 NPE,又区别于“加载失败”
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
在关键路径做初始化断言
对核心业务对象,在进入主流程前快速验证必填字段是否已设置:
• 在服务方法开头调用 order.validateRequiredFields()
• 使用 Lombok 的 @NonNull 配合构造函数或 Builder 模式,把校验提到编译期
• 数据库实体映射时,配置 MyBatis-Plus 的 @TableField(fill = FieldFill.INSERT),确保插入时字段不为空
立即学习“Java免费学习笔记(深入)”;
警惕默认值在反序列化和分支逻辑中的静默影响
攻击者或旧客户端不传字段时,int status 得到 0,Boolean enabled 得到 null——同一笔数据,两个字段的“确定性”完全不同:
• 统一 DTO 中同名字段类型必须一致(推荐全用包装类)
• 权限校验逻辑别写 if (!isAdmin),应改为 if (isAdmin == null || !isAdmin)
• 版本号、状态码等关键字段,反序列化后立即检查是否为默认值(如 if (version == 0) throw new InvalidDataException("version missing"))

















