谓词<? super X>.and(Predicate<? super X>) 不适用于参数 Predicate<?超X>

Predicate<? super X>.and(Predicate<? super X>) is not applicable for the argument Predicate<? super X>

我必须对实现 Predicate<MoneyOperation> 的业务对象执行 and()

出现问题的代码是 and() 调用的行:

        Predicate<? super MoneyOperation> predicate =
           new MoneyOperationDateWithRadioButtonsPredicate(newv, 
                  thisDayRdBtn.getValue(), date);

        filteredData.setPredicate(filteredData.getPredicate().and(predicate));

错误:

The method and(Predicate<? super capture#14-of ? super MoneyOperation>) 
in the type Predicate<capture#14-of ? super MoneyOperation> is not applicable 
for the arguments (Predicate<capture#15-of ? super MoneyOperation>)

虽然当我将 predicate 传递给 setPredicate() 而不调用 and() 编译器不会引发任何错误。

MoneyOperationDateWithRadioButtonsPredicate class:

public class MoneyOperationDateWithRadioButtonsPredicate extends MoneyOperationFieldPredicate<LocalDate> { ... }

MoneyOperationFieldPredicate class:

public abstract class MoneyOperationFieldPredicate<T> implements Predicate<MoneyOperation> { ... }

这只是类型系统的限制,因为 Java 没有使用 Predicate 没有生产者方法(在 PECS 的意义上)这一事实来处理输入不同。

考虑两个 List<? super Integer> 实例:你不能做 list1.addAll(list2),原因与你不能在这里做 predicate1.and(predicate2) 的原因相同:这是为了防止 list1 可能是 List<Integer>,而 list2List<Object>:您不应将对象添加到您希望只包含整数的列表中。

这是 List 的一个实际问题,因为 List 有生产者方法(例如 List.get(int)),即旨在为您提供特定类型实例的方法。 Predicate 只有消费者方法(一个,准确地说,Predicate.test<T>),所以不会有 Predicate 给你一个意外类型的对象的情况。

但是,编译器不考虑 class 是否没有生产者方法(或没有消费者方法):它假设两者都存在(实际上,它们可能存在于 subclasses ), 所以它会阻止你这样做。也许很烦人,但事实就是如此。

最简单的方法是构造一个 lambda 来显式测试两个谓词:

setPredicate(a -> predicate1.test(a) && predicate2.test(b))

你也许可以使用这个奇怪的技巧:

setPredicate(Stream.of(predicate1, predicate2).map(a -> a).reduce(Predicate::and))

但无论是按规范还是按怪癖实施,我都不太满意。

这里的问题是捕获。让我们看看这些限制意味着什么:

Predicate<? super MoneyOperation> 是一个谓词,可以采用 MoneyOperation 或者它可能是超级 class 和 returns 布尔值。 这意味着它可以是一个 Predicate<Object> 接受一个 Object 和 returns 一个布尔值。

现在有一个潜在的问题:
假设 MoneyOperation 扩展了 GenericOperation 并实现了 SomeInterface.
第一个 Predicate<? super MoneyOperation> 实际上可能是 Predicate<GenericOperation>,第二个 Predicate<? super MoneyOperation> 可能是 Predicate<SomeInterface>。 (Java 编译器无法判断) 将 MoneyOperation 传递给它们两者都很好,但将它们组合起来需要将其类型限制为 Predicate<MoneyOperation>。虽然这对 Predicate 没问题,但可能不适用于其他情况。

这就是 Java 不允许这样做的原因。
如果您知道它是一个,请使用 Predicate<MoneyOperation>