IllegalStateException是状态机的设计语言而非错误,用于显式拒绝非法操作;需在方法入口用枚举校验状态并抛出含实际/期望状态及方法名的异常,禁用canXxx查询,保障原子性,不捕获而重预防与文档化。

状态机中用IllegalStateException明确拒绝非法操作
在状态机架构里,IllegalStateException不是错误,而是设计语言。它用来清晰表达“这个动作在此刻不允许”,比如订单从“已发货”直接跳转到“待支付”,或播放器在“暂停”状态下调用resume()前又执行了一次play()。这种异常不掩盖问题,而是把状态约束显式暴露出来,让调用方立刻意识到逻辑越界。
方法入口做状态断言,不依赖外部判断
每个可变行为(如start()、cancel()、confirm())都应在第一行检查当前状态是否允许执行:
- 用枚举定义状态(如
State.CREATED、State.PROCESSING、State.COMPLETED),避免布尔值带来的语义模糊 - 校验失败时抛出带三要素的消息:实际状态、期望状态、被调用方法名,例如
new IllegalStateException("Cannot call confirm() in state PROCESSING; expected PENDING") - 不提供
canConfirm()这类查询方法——防止检查后状态被并发修改,导致竞态
配合线程安全与原子性保障
多线程环境下,状态检查和后续操作必须是原子的:
- 简单状态用
volatile State state配合if (state == EXPECTED) { ... },但仅适用于无副作用的单步判断 - 复合操作(如“若为PENDING则设为PROCESSING并触发回调”)推荐用
AtomicReference<state></state>配合compareAndSet - 在抛异常前记录DEBUG日志,包含对象ID、线程名、时间戳,便于回溯状态错乱源头
不捕获,不试探,只预防和文档化
不要用try-catch包围可能抛IllegalStateException的方法来“探测状态”。这违背其设计本意,也掩盖了流程缺陷。正确做法是:
立即学习“Java免费学习笔记(深入)”;
- 所有状态转移逻辑由内部方法封装,外部只能触发合法动作
- 在JavaDoc中明确标注每个方法的前置状态要求,例如
@throws IllegalStateException if state is not PENDING - 用单元测试覆盖全部非法状态调用路径,确保异常按预期抛出


















