构造方法中抛出未捕获异常可阻止对象创建;校验须在字段赋值前完成;应使用语义明确的异常类型;禁止在构造中执行不可回滚操作;复杂校验推荐用私有构造+静态工厂。

直接抛出异常就能阻止对象创建。Java 规定:只要构造方法执行过程中抛出未捕获的异常,JVM 就不会完成对象实例化——new 表达式根本不会返回有效引用,栈上连对象地址都不会压入,更不存在“半成品对象”被外部持有或使用的问题。
校验必须放在赋值前
参数合法性检查要写在任何字段赋值操作之前。一旦字段被写入,即使后续抛异常,对象内部状态已部分变更,可能留下不可预测的中间态。
- 错误写法:先 this.name = name; 再 if (name == null) throw ... —— 此时 name 字段已被设为 null,对象已处于非法但可访问的状态
- 正确写法:开头就校验,通过后才开始初始化字段
用合适的异常类型表达语义
不要笼统 throw new Exception()。不同错误应匹配不同异常,让调用方快速理解问题本质:
- 业务规则类错误(如年龄为负、ID为空、分数超限)→ IllegalArgumentException
- 不可为空的引用类型缺失 → NullPointerException(Java 8+ 可配合 @NonNull 注解增强提示)
- 外部资源加载失败(如读配置文件、连数据库)→ 声明 throws IOException 或自定义受检异常(如 ConfigLoadException)
避免构造函数中触发危险行为
有些操作一旦启动就无法回滚,哪怕立刻抛异常也已造成副作用:
- 禁止在构造中启动线程、发布 this 引用、写入数据库或发送消息
- 禁止调用可被子类重写的方法(如 protected 方法),否则子类逻辑会在自身字段还未初始化时被执行
- 资源类(如文件流、连接池客户端)若需打开资源,应在校验通过后立即获取,并确保失败时能清理(推荐 try-with-resources)
复杂校验建议改用静态工厂
当校验需要查数据库、远程调用或涉及多步事务时,构造函数难以安全处理中间状态和回滚。此时应退一步:
- 把构造函数设为 private,防止直接 new
- 提供 public static 工厂方法(如 User.createVerified(email)),内部做完整校验与清理
- 工厂方法可统一记录日志、上报指标、包装异常,也更利于单元测试模拟各种失败路径
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











