面向对象中非法输入应前置拦截而非依赖异常捕获:构造阶段拒绝非法值,方法入口统一校验,状态流转主动约束,类型系统与契约先行保障合法性。

面向对象结构中处理非法输入,关键不是等异常发生再捕获,而是通过设计约束和分层校验,在问题进入核心逻辑前就拦截或转化。重点在于把防御点前移到对象创建、方法入口和状态流转环节,而不是堆砌 try-catch。
构造阶段就拒绝非法值
对象一旦创建成功,应默认处于有效状态。因此非法输入必须在构造器或工厂方法中被识别并拒绝:
- 对必填字段做非空检查,null 或空字符串直接抛 IllegalArgumentException,不构造对象
- 数值型参数超出业务范围(如年龄为负数、订单金额为 NaN)立即拦截
- 枚举或状态码类参数,用 valueOf() + try-catch 封装成明确失败,或改用静态工厂方法返回 Optional
- 避免在构造器中调用可被子类重写的方法,防止子类在对象未完全初始化时访问非法字段
方法入口统一守门
每个对外暴露的 public 方法,都应视为独立的输入边界:
- 使用 @NotNull、@NotBlank、@Min/@Max 等注解配合 Bean Validation,在框架层自动校验(如 Spring 的 @Valid)
- 手动校验优先用 Objects.requireNonNull()、Objects.requireNonNullElse(),比 if (x == null) 更简洁且语义清晰
- 集合类参数先判空再判元素合法性:空集合可接受,但含 null 元素或类型错误元素需提前报错
- 避免把校验逻辑分散在方法内部多处,统一放在开头形成“守门员”模式
状态流转中主动约束
面向对象强调封装与状态一致性,非法输入常表现为状态跃迁违反业务规则:
- 状态机类(如订单 Order)的变更方法(如 confirm()、cancel())应检查当前状态是否允许该操作,否则抛 IllegalStateException
- 用 private final 字段 + 不可变 getter 暴露状态,禁止外部直接修改;所有状态变更走受控方法
- 涉及外部输入驱动的状态更新(如支付回调),先解析再校验签名、时间戳、幂等键,确认无误才触发内部状态迁移
- 对可能产生副作用的操作(如扣库存),前置执行预校验(check-then-act),而非依赖最终一致性补偿
类型系统与契约先行
最有效的防御是让非法输入根本无法构造出来:
- 用 Value Object 封装原始类型:如 Email、Money、Phone,其构造器内完成格式、范围、非空校验,实例即合法
- 接口定义明确契约:方法参数用具体类型而非 Object 或 String,返回值用 Optional 或 Result
显式表达可能失败 - 泛型约束加强编译期检查:如
、 >,减少运行时类型错误 - 配合 Lombok @Value 或 record(Java 14+)自动生成不可变结构,降低误改风险











