# 类型、OOP 与 API 设计 ## 类型与相等性 - **必须**:包装类型使用 `equals` 或 `Objects.equals` 比较值,不使用 `==`;警惕缓存范围造成的偶然相等。 - **必须**:`BigDecimal` 使用字符串或精确来源构造;数值大小用 `compareTo`,需要比较值与 scale 时才用 `equals`。 - **必须**:货币、比例和计量值明确精度、舍入方式与单位;禁止用 `double` 承载精确金额。 - **必须**:重写 `equals` 时同时重写 `hashCode`,并验证对称性、传递性和集合行为。 - **推荐**:用领域类型、枚举和受约束构造器替代多个语义不明的 `String`、`int` 参数。 - **必须**:类型转换前检查范围和语义;不得以强制转换静默截断数值。 ## 空值与返回值 - **必须**:明确参数与返回值的 nullability;不得依靠调用方猜测。 - **推荐**:返回空集合或空数组而非 `null`;不要为避免判断而创建语义虚假的空领域对象。 - **推荐**:`Optional` 主要用于可能缺失的返回值;不要默认用于实体字段、DTO 字段、方法参数或集合元素。 - **必须**:禁止无条件链式解引用可能为空的对象;在边界校验或使用清晰分支表达缺失语义。 - **必须**:不要用断言校验外部输入,因为生产环境可能禁用断言。 - **推荐**:在系统边界尽早校验参数;项目支持 Bean Validation 时优先使用 `@Valid`、`@NotNull`、`@NotBlank`、`@Size` 等声明式校验。 - **推荐**:内部前置条件优先复用项目已有校验工具;只有需要定制业务错误码或分支处理时才手写空值判断。 - **必须**:不得仅为判空新增依赖。 - **推荐**:项目没有现成判空工具时,对象使用 `obj == null`,集合使用 `collection == null || collection.isEmpty()`,Map 使用 `map == null || map.isEmpty()`;只有项目已经依赖 Apache Commons Collections 时,才使用 `CollectionUtils.isEmpty()` 或 `MapUtils.isEmpty()`。 ## OOP 与封装 - **必须**:遵循单一职责和最小可见性;字段默认 `private`,只暴露必要 API。 - **必须**:构造完成后对象应满足不变量;不要暴露可变内部集合、数组或日期对象。 - **推荐**:优先组合而非继承;继承只用于稳定的 is-a 关系和可替换契约。 - **必须**:覆写方法使用 `@Override`;可变参数只用于同类型、同语义参数,不使用 `Object...` 逃避类型设计。 - **必须**:构造器不得启动线程、访问远程资源或发布未完全构造的 `this`。 - **推荐**:不可变对象优先;必要时使用 defensive copy,并确保集合元素也符合可变性预期。 - **推荐**:接口保持内聚,不创建囊括无关操作的“大而全” Service 或 Util。 ## API 与兼容性 - **必须**:公共 API 明确输入校验、返回语义、错误模型、幂等性和副作用。 - **必须**:单资源路径已经通过 `@PathVariable` 确定资源身份时,不得再使用可选查询参数表达另一套资源标识。不同标识的查询入口应拆分;若多个标识共同构成业务校验条件,应明确必填性、匹配规则和错误语义。 - **必须**:新增重载时检查 `null`、lambda、自动装箱和可变参数是否造成调用歧义。 - **必须**:修改 DTO、枚举、JSON 字段、RPC 签名或异常类型前评估调用方兼容性。 - **推荐**:返回接口类型而非具体集合实现;不要泄漏 ORM 实体、框架上下文或内部异常。 - **推荐**:避免布尔参数控制多个行为,优先使用有语义的方法、枚举或选项对象。 - **必须**:不得以反射、原始类型或未检查转换绕过编译器,除非边界隔离、理由明确并有测试。 ## Lombok - **必须**:仅在项目已采用 Lombok 时使用,不为风格统一单独引入依赖。 - **参考**:DTO/VO 可使用 `@Data`;使用前检查可变性、相等性和敏感字段,存在特殊约束时改用明确的 `@Getter`、`@Setter`、`@EqualsAndHashCode` 或 `@ToString`。 - **推荐**:实体类和值对象避免使用 `@Data`;按项目约定组合 `@Getter`、`@Setter`、`@Builder`、`@NoArgsConstructor` 和 `@AllArgsConstructor`,且不得绕过领域不变量或 ORM 构造约束。 - **推荐**:除非继承关系确有需要,不设置 `@EqualsAndHashCode(callSuper = true)`。 - **必须**:`toString` 不得暴露敏感字段,也不得触发懒加载或递归引用。