密封接口配合泛型可高效模拟和类型,通过受限继承、类型参数约束与模式匹配协同实现编译期穷尽检查与语义清晰表达。

密封接口(sealed interface)配合泛型,确实能高效模拟和类型(Sum Type),也就是“要么是 A,要么是 B,仅此二者”的语义。这不是简单套用语法,关键在于用 受限继承 + 类型参数约束 + 模式匹配 三者协同,让编译器强制穷尽、让调用方一眼看懂数据形态。
用 sealed interface 定义明确的分支边界
和类型的核心是“有限且封闭的选项集合”。Java 17+ 的 sealed interface 正为此而生——它不允许外部模块新增实现类,从而保证所有可能值都在可控范围内。
- 声明时显式列出所有允许的子类型,例如:
sealed interface Result<T> permits Success<T>, Failure<T> - 每个子类型必须是 final、sealed 或 non-sealed,但推荐全部设为 final(避免意外扩展)
- 不写 permits 会失去编译期检查能力;permit 列表漏掉某个实现类,编译直接报错
泛型参数绑定不同分支的语义含义
泛型不是装饰,而是把“类型意图”注入每个分支。比如 Success<String> 和 Failure<IOException> 中的类型参数,分别承载成功值的类型和失败原因的类型,比裸写 Success / Failure 更自解释。
- Success<T> 可携带 T 类型的有效结果,构造时必须提供非 null 值
- Failure<E extends Throwable> 可限定错误类型(如只接受 RuntimeException 子类),增强契约表达力
- 避免使用原始类型或 Object:泛型擦除后仍靠编译期约束保意义,运行时也更易调试
配合 switch 表达式实现类型安全的模式解构
Java 21+ 的 switch 表达式支持对 sealed 类型进行穷尽匹配,这是和类型落地的关键一步——编译器能验证你是否覆盖了所有分支,杜绝漏处理。
- 写
return switch (result) { case Success s -> s.value(); case Failure f -> f.error().getMessage(); }; - 如果未来新增一个分支(如 Timeout<T>),现有 switch 会立刻编译失败,强迫你审视逻辑完整性
- case 标签自动推导具体类型(s 是 Success<?>,f 是 Failure<?>),无需手动 instanceof + 强转
配套工具方法提升可读性与复用性
光有结构不够,还需封装常见操作,让业务代码聚焦“做什么”,而不是“怎么拆”。
- 在 sealed interface 中定义默认方法,如
map<U>(Function<T,U> f)或fold(U ifSuccess, Function<E,U> ifFailure) - 提供静态工厂方法
Result.success(value)和Result.failure(cause),隐藏 new 调用细节 - 重写 toString() 显式输出分支名和内容,日志中一眼识别是 Success 还是 Failure 及其载荷


















