Java中AssertJ satisfies方法捕获类及代码编译失败原因问询
AssertJ satisfies方法相关问题解答
一、satisfies方法作用于List时的捕获类
当AssertJ的satisfies方法应用于List时,它直接捕获列表本身的实例(泛型类型为List<E>,E是列表元素的类型)。satisfies接收一个Consumer<? super List<E>>类型的参数,不会对列表做额外包装,只是让你传入自定义逻辑来验证列表的状态。
二、代码编译失败原因分析
环境信息
- Java版本:openjdk 11.0.20 2023-07-18
- AssertJ版本:3.24.2(问题在3.21.0版本已存在)
问题代码
package example; import org.junit.Test; import java.util.List; import static org.assertj.core.api.Assertions.*; public class ExampleTest { public interface ICommon { } public static class TypeA implements ICommon { // assume overridden equals } public static class TypeB implements ICommon { // assume overridden equals } @Test public void test() { final List<ICommon> actual = List.of(new TypeA(), new TypeB()); final List<ICommon> expected = List.of(new TypeA()); final Iterable<? extends ICommon> thisCompiles = expected; // no problems /* * 'containsAnyElementsOf(java.lang.Iterable<? extends capture<? extends example.ExampleTest.ICommon>>)' * in 'org.assertj.core.api.AbstractIterableAssert' cannot be applied to * '(java.util.List<example.ExampleTest.ICommon>)' */ assertThat(actual).satisfies(r -> assertThat(r).containsAnyElementsOf(expected)); /* * * 'containsAnyElementsOf(java.lang.Iterable<? extends capture<? extends example.ExampleTest.ICommon>>)' * in 'org.assertj.core.api.AbstractIterableAssert' cannot be applied to * '(java.lang.Iterable<capture<? extends example.ExampleTest.ICommon>>)' */ assertThat(actual).satisfies(r -> assertThat(r).containsAnyElementsOf(thisCompiles)); } }
编译失败原因
这是泛型捕获与方法签名不兼容导致的问题:
AssertJ的containsAnyElementsOf方法签名是:
public SELF containsAnyElementsOf(Iterable<? extends E> other)
在satisfies的lambda里调用assertThat(r)时,编译器对r的类型推断出现了嵌套通配符的冲突:
actual是List<ICommon>,所以satisfies的lambda参数r默认被推断为List<ICommon>。- 但
assertThat(r)返回的AbstractIterableAssert内部,泛型被捕获为Iterable<? extends ICommon>,进一步导致containsAnyElementsOf期望的参数类型变成Iterable<? extends capture<? extends ICommon>>。 - 而你传入的
expected是List<ICommon>,thisCompiles是Iterable<? extends ICommon>,这两者都无法匹配嵌套的捕获通配符类型——编译器无法确认ICommon和capture<? extends ICommon>的兼容性,因此报错。
简单说就是:嵌套的泛型通配符让编译器卡壳了,它没法自动把外层的通配符类型转换成内层的捕获类型。
解决办法
- 显式指定lambda参数的类型,帮编译器明确推断方向:
assertThat(actual).satisfies((List<ICommon> r) -> assertThat(r).containsAnyElementsOf(expected));
- 或者直接简化代码,跳过
satisfies直接断言:
assertThat(actual).containsAnyElementsOf(expected);
内容的提问来源于stack exchange,提问作者Jon Bristow
相关产品推荐
相关产品推荐

