【问题标题】:Java 8 type inference involving Booleans涉及布尔值的 Java 8 类型推断
【发布时间】:2014-12-06 01:13:14
【问题描述】:

考虑以下代码:

class Predicate {
    public boolean eval(EvaluationContext ec) { /* logic here */ }
}

// later ...
List<Predicate> preds = new List<>( /* some predicates here */ );

// now let's use Stream<> to implement the AND logical connective:
// VERSION A:
Boolean resultA = preds.stream()
                       .map(p -> p.eval(context))
                       .reduce(Boolean.TRUE, (a,b) -> Boolean.logicalAnd(a,b));
// Oops: the code above doesn't compile ...   
// Error: incompatible types: java.lang.Object cannot be converted to boolean

// VERSION B:   (add an intermediate variable with explicit type)
Stream<Boolean> v = _children.stream().map(p -> p.eval(context));
Boolean resultB = v.reduce(Boolean.TRUE, (a,b) -> Boolean.logicalAnd(a, b) );
// compiles just fine...

所以,我的问题是:

版本 A 的结构有什么问题导致 Java 编译器无法正确推断 map() 的结果类型?这是 Java 中类型推断算法的限制吗?如果是这样,是否有更好的方法来编写此代码以使类型推断成功?

【问题讨论】:

  • 两者都适用于 Eclipse。
  • 补充说明:这里使用的是在 OpenJDK 下运行的 javac 版本 1.8.0_25。
  • 你能举一个完整的例子吗? (比如没有new List,显示_children 是什么等)它也适用于1.8.0_20 Oracle JDK。
  • 为了解决你的最后一个问题,我可能会使用preds.stream().allMatch(p -&gt; p.eval(context))
  • 在 8u25、Windows 7 x64 上为我工作。你用什么平台?另外,请添加可编译的示例。

标签: java generics compiler-errors java-8 type-inference


【解决方案1】:

您的代码与jdk1.8.0_05jdk1.8.0_20jdk1.8.0_25jdk1.8.0_40 (beta) 一起编译得很好,并且没有理由假设其他版本存在问题。当您修复虚构代码的其他错误或将您提供给编译器的真实代码发布时,也许它会有所帮助。

例如如果List 引用java.util.List 并且您的示例代码不包含context 的声明,则您不能说new List&lt;&gt;。如果找不到context,编译器确实会产生一个“类型不兼容”的后续错误,一旦你修复了其他错误,它就会消失。令人惊讶的是,您的第二个示例使用了 _children 而不是 preds,因此它源自很可能不存在此类编译器错误的不同上下文。

顺便说一句,你的 lambda 表达式 (a,b) -&gt; Boolean.logicalAnd(a,b) 有点奇怪。要么使用表达式,例如(a,b) -&gt; a &amp;&amp; b 或类似 Boolean::logicalAnd 的方法引用。

但无论哪种方式,都不推荐使用归约。您可以通过使用短路方法获得更好的性能,例如_children.stream().allMatch(p -&gt; p.eval(context))logical and_children.stream().anyMatch(p -&gt; p.eval(context))logical or

【讨论】:

    【解决方案2】:

    你有什么理由不能使用

    将所有谓词组合在一起
    Predicate<EvaluationContext> finalTest = preds.stream()
                                                  .reduce(((p)->true), Predicate::and);
    

    那么你就有了一个谓词,你可以在编译一次之后保存并重复使用它来测试任意数量的上下文。

    重新阅读后,我注意到您的 Predicate 类不是 java.util.function.Predicate。为了实现我所描述的,您需要稍微改变您的 Predicate 类以使其实现 Predicate 接口:

    public class Predicate implements java.util.function.Predicate<EvaluationContext>{
        public boolean eval(EvaluationContext ec) { /* logic here */ }
    
        @Override
        public boolean test(EvaluationContext t) {
            return eval(t);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-20
      • 2017-12-07
      • 1970-01-01
      • 2014-05-17
      • 1970-01-01
      • 2014-08-17
      相关资源
      最近更新 更多