【问题标题】:java.util.function.Predicate#and and Groovy 2.2 closuresjava.util.function.Predicate#and 和 Groovy 2.2 闭包
【发布时间】:2014-04-29 20:32:17
【问题描述】:

我有这个运行良好的 Java 8 代码:

//Java 8
@Test public void testPredicates(){
    Predicate<Integer> p1 =  (i) -> true;
    Predicate<Integer> p2 =  (i) -> true;
    Predicate<Integer> p3 =  p1.and(p2);
    List<Integer> is = new ArrayList<>();
    is.add(1);
    is.add(2);
    assertTrue(is.stream().allMatch(p1.and(p2)));
}

我在 Groovy (2.2) 中最接近它的是:

//Groovy 2.2
@Test
void test(){
    Predicate<Integer> p1 = { i -> true}
    Predicate<Integer> p2 = {i -> true}
    Predicate<Integer> p3 = p2.and(p1)
    List<Integer> is = new ArrayList<>()
    is.add(1)
    is.add(2)
    assert(is.stream().allMatch(p1.and(p2)))
}

Groovy 代码在调用and 方法的那一行出现以下错误:

java.lang.ClassCastException: java.lang.Boolean 
    cannot be cast to java.util.function.Predicate

如果我只用assert(is.stream().allMatch(p1)) 替换断言,则测试成功完成。问题是在谓词上调用and 方法。

在调试器中检查例如p2,我可以看到它的类型为OneParameterTest$_test_closure2。反编译字节码可以验证这一点。

虽然我不确定,但我有一种感觉,这与隐式闭包强制有关(请参阅 http://groovy.codehaus.org/Groovy+2.2+release+notes)。

有没有办法编写 Groovy 代码,以便将谓词创建为 java.util.function.Predicate 的真实实例?

【问题讨论】:

  • 如果你写allMatch(p3),groovy 版本是否有效?
  • 关于您的问题的两个小问题:1) 您从未使用过p3,2) 在 Java 8 中您有 p1.and(p2),在 Groovy 中您在 p3 中有 p2.and(p1),请注意颠倒的顺序。
  • 优点,但都不是问题。在谓词上调用“and”是问题所在。
  • 尝试使用 Groovy 2.3(支持 Java 8),我得到了相同的结果。也许将此发布到 groovy-user 邮件列表?
  • 好的,我已经发布了 - 让我们看看是否有任何回复...

标签: groovy java-8 predicate


【解决方案1】:

有没有办法编写 Groovy 代码以便它创建谓词 作为 java.util.function.Predicate 的真实实例?

您正在做的是创建 Predicate 的真实实例。问题是您创建它们的方式实际上只对单一方法接口有用。 Predicate 定义了几种方法。有几种方法可以解决这个问题。也许最简单的就是利用 Groovy 的 Map 来支持接口。下面的代码只考虑了“and”和“test”,但您可以提供您实际调用的任何内容并省略其他代码。

很难从你的代码 sn-p 中说出你真正想要完成的事情,但只是为了解决你编写的特定测试,你应该能够做这样的事情。测试方法都被硬编码为在此处返回 true,就像在您的测试中一样,但您可能在那里有真正的逻辑。

Predicate<Integer> p1 = [test:{ t -> true},
                         and: { Predicate other -> [test: { t -> true}] as Predicate}] as Predicate

// in your example you are never calling p2.and(...), but
// it is included here for consistency with the one above...
Predicate<Integer> p2 = [test:{ t -> true},
                         and: { Predicate other -> [test: { t -> true}] as Predicate}] as Predicate

// it isn't clear why you are creating p3, but you can...
Predicate<Integer> p3 = p1.and(p2)
List<Integer> is = new ArrayList<>()
is.add(1)
is.add(2)
assert(is.stream().allMatch(p1.and(p2)))

【讨论】:

  • 我意识到这个例子并没有真正做任何有用的事情,但它确实做了原始帖子中的测试试图做的事情。也许你可以从这里弄清楚,或者如果你能更好地描述真正的问题,我可以给你一个解决方案。无论如何,我希望这会有所帮助。
【解决方案2】:

实际上,问题在于 Groovy 2.3 的早期版本忽略了接口中定义的默认方法。

来自 Groovy 2.3 release notes

Groovy 2.3 不支持 Java 8 提供的新语法结构 (例如 lambdas、方法引用、接口中的默认方法、 等),但您已经可以很好地使用 JDK 8 提供的新 API, 甚至使用 Groovy 闭包代替 Java 8 lambda。

作为GROOVY-7104 的一部分,它在 2.3.8 和 2.4 中已修复(至少对于上述情况)

【讨论】:

    猜你喜欢
    • 2011-03-15
    • 1970-01-01
    • 2015-10-12
    • 2011-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-30
    • 1970-01-01
    相关资源
    最近更新 更多