流减少不兼容的类型

use*_*896 3 java reduce java-8 java-stream

我正在尝试创建一个包含多个谓词并减少它们的查找程序:

public static <T extends BusinessInterface> Collection<T> findOr(
    Context pContext, Class<T> pClass, Predicate<? super T>... pPredicates) {
  Predicate<? super T> lReducedPredicate =
      Arrays.asList(pPredicates).stream().reduce(Predicate::or).orElse(r -> false);
  return find(pContext, pClass, lReducedPredicate);
}
Run Code Online (Sandbox Code Playgroud)

不幸的是我得到以下编译错误:

谓词lReducedPredicate = Arrays.asList(pPredicates).stream().reduce(Predicate :: or).orElse(r - > false); 不兼容的类型:谓词不能转换为谓词,其中T是一个类型变量:T扩展了方法findOr(Context,Class,Predicate ...)中声明的BusinessInterface,其中CAP#1,CAP#2是新的类型变量:CAP# 1扩展Object super:T从捕获?超级T CAP#2扩展了Object super:T从捕获?超级T

我在Eclipse中没有错误,我不知道出了什么问题.

任何帮助真的很感激:).

Hol*_*ger 7

解决这个问题的一种方法是使用

public static <T extends BusinessInterface> Collection<T> findOr(
    Context pContext, Class<T> pClass, Predicate<? super T>... pPredicates) {
  Predicate<? super T> lReducedPredicate = Arrays.asList(pPredicates).stream()
    .reduce((a,b) -> t -> a.test(t) || b.test(t)).orElse(r -> false);
  return find(pContext, pClass, lReducedPredicate);
}
Run Code Online (Sandbox Code Playgroud)

虽然您不能orPredicate<? super T>另一个实例上调用该方法Predicate<? super T>作为参数,但您可以创建相同的函数or,自己返回,因为将T实例传递给任一test方法都是有效的.


And*_*ner 6

你的代码在intellij中适用于我,但不适用于ideone,这很奇怪.

编译器错误的原因是您正在尝试执行此操作:

Predicate<? super T> a = null;
Predicate<? super T> b = null;
a.or(b);  // Compiler error!
Run Code Online (Sandbox Code Playgroud)

因为在两个单独的通配符ab,编译器不能保证类型界限是兼容的,因为这些通配符不一定相同.

无论如何,试试这个奇怪的伎俩:

Arrays.asList(pPredicates)
    .stream()
    .map(a -> a)  // Here!
    .reduce(Predicate::or)
    .orElse(r -> false);
Run Code Online (Sandbox Code Playgroud)

插入此行允许它转换为与类型约束匹配的类型.

  • 但*为什么*.`map(a - > a)`解决问题? (7认同)
  • @Holger blimey,即使*你*无法解释它,也值得远离它.我真的很希望能够开悟. (4认同)
  • @Holger我没有很好的解释.我的直觉是它给类型推理逻辑提供了更多的灵活性来选择一个与`reduce(Predicate ::或)`兼容的类型.如果你能在没有我的手工的情况下解释它,我会很高兴;) (2认同)
  • @ user1567896:更喜欢我的答案的主要原因是我们知道它为什么有效.只要我们不知道为什么`map(a - > a)`技巧有效,我们就必须考虑到这可能只是一个在较新版本中修复的编译器错误.仍然使用`Predicate ::或'的更清洁的替代方案是`Predicate <T> lReducedPredicate = Arrays.asList(pPredicates).stream().reduce(r - > false,Predicate :: or,Predicate :: or);` (2认同)
  • @Holger我已经发布了[一个单独的问题](/sf/ask/3145467391/)具体询问这个问题. (2认同)