我目前正在使用一个库方法,该方法将具有通用通配符类型的功能接口作为方法参数(特别是在AssertJ库中)。我发现当我传递一个使用除通配符类型参数以外的任何类型的 lambda 方法参数时,我得到一个编译错误。例如,如果方法是,当我调用.RecursiveComparisonAssert.withEqualsForFields(BiPredicate<?,?> equals, String... fieldLocations)
Object
sameInstant(Instant i1, Instant i2)
withEqualsForFields(this::sameInstant, "someField")
简化示例
作为这种现象的一个更简单的示例,不需要使用任何特定的库来重现,请使用Predicate<?>
方法参数采取以下场景:
public class WildcardLambda {
public static void main(String[] args) {
wildcardPredicateInput(WildcardLambda::objectPredicate);
wildcardPredicateInput(WildcardLambda::stringPredicate); // Fails
wildcardPredicateInput((Predicate<String>) WildcardLambda::stringPredicate);
wildcardPredicateInput(input -> stringPredicate(input));
genericPredicateInput(WildcardLambda::objectPredicate);
genericPredicateInput(WildcardLambda::stringPredicate);
}
private static void wildcardPredicateInput(Predicate<?> predicate) {}
private static <T> void genericPredicateInput(Predicate<T> predicate) {}
private static boolean objectPredicate(Object input) { return true; }
private static boolean stringPredicate(String input) { return true; }
}
尝试将 lambda 传递给Predicate<String>
接受 a 的方法会Predicate<?>
导致编译错误:
$ javac WildcardLambda.java -Xdiags:verbose
WildcardLambda.java:6: error: method wildcardPredicateInput in class WildcardLambda cannot be applied to given types;
wildcardPredicateInput(WildcardLambda::stringPredicate); // Fails
^
required: Predicate<?>
found: WildcardLa[...]icate
reason: argument mismatch; invalid method reference
method stringPredicate in class WildcardLambda cannot be applied to given types
required: String
found: Object
reason: argument mismatch; Object cannot be converted to String
1 error
但是,传递一个 lambdaPredicate<Object>
或显式转换 lambda 以Predicate<String>
成功。此外,如果将其传递给需要Predicate<T>
.
为什么这种 lambda 用法会导致编译错误?我在JLS中是否忽略了某些内容,表明这应该无法编译?