assertj 的 assertthat 方法本身不直接暴露 pecs 原则,但在配合 extracting、filteredon 等泛型工具提取属性时,pecs 原则自然浮现:extracting 作为“生产者”需用 ? extends t,而 filteredon 作为“消费者”需用 ? super t。

AssertJ 的 assertThat 方法本身不直接暴露 PECS 原则,但在你用它配合泛型工具(如 extracting、filteredOn 或自定义断言)提取属性时,PECS 原则会自然浮现——尤其当你处理集合、构建可复用的断言逻辑或封装通用校验方法时。
提取属性时的“生产者”场景:? extends T
当你调用 extracting("name") 或 extracting(Person::getName) 从一个集合中读取字段值,AssertJ 实际上是在“消费”集合元素并“产出”属性值。此时若你把被断言的集合声明为 List extends Person>,AssertJ 就能安全地调用 get(0).getName() ——因为编译器已保证每个元素至少是 Person 类型,其 getName() 方法一定存在。
- ✅ 允许传入
List<student></student>、List<teacher></teacher>或List<person></person>到同一个assertThat(...).extracting("name")链中 - ❌ 不能往这个集合里 add 新元素(AssertJ 也不做这事),这正符合
? extends T的只读约束 - ⚠️ 若你在自定义断言方法中接收参数,写成
void assertNames(List extends Person> people),就比List<person></person>更灵活且类型安全
构建通用断言方法时的“消费者”场景:? super T
当你编写一个复用的断言工具方法,比如批量验证 ID 是否存在于某个目标容器中,该容器可能用于接收多种子类型 ID:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- ✅ 可以定义为
void assertIdsIn(Collection super Long> allowedIds, List extends Entity> entities) - 这样
allowedIds能接受Set<long></long>、List<number></number>甚至Collection<object></object>,只要能容纳Long - 而
entities是只读生产者,用? extends Entity支持Product、User等子类列表 - AssertJ 的
contains()或isIn()内部逻辑虽不暴露泛型参数,但你封装的外围方法可以靠 PECS 提升兼容性
与 AssertJ 链式调用结合的关键点
AssertJ 的 fluent API 本身基于具体泛型(如 AbstractListAssert),但它的扩展点(如 Satisfies、usingComparator、自定义 Condition)常需你手动处理泛型边界:
- 写一个
Condition super Person>,就能用于Student、Teacher等所有子类实例的校验 - 用
extracting("id", Long.class)时,AssertJ 会尝试将结果转为List<long></long>;若原始集合是List extends User>,提取过程仍安全,因为User.getId()返回Long是确定的 - 避免反模式:不要为了“适配”而用原始类型
List或Object,那样失去编译期检查,反而增加运行时ClassCastException风险
实际调试中的典型报错与修复
常见编译错误往往暴露了你无意中违反了 PECS:
-
error: incompatible types: List<student> cannot be converted to List<person></person></student>→ 改用List extends Person>作为方法参数 -
error: method extractProperty in class AbstractListAssert cannot be applied to given types→ 检查 lambda 表达式返回类型是否一致,确保Student::getName和Teacher::getName都返回相同上界类型(如String) - 在
filteredOn("status", "ACTIVE")后接extracting("id")失败?确认status字段在所有子类中定义方式一致(最好抽取为接口或基类字段)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










