以下测试失败
@Test
public void test() {
Function<String, Integer> foo = Integer::parseInt;
Function<String, Integer> bar = Integer::parseInt;
assertThat(foo, equalTo(bar));
}
有没有办法让它通过?
编辑:我会尽力让自己更清楚自己要做的事情。
让我说我有这些课程:
class A {
public int foo(Function<String, Integer> foo) {...}
}
class B {
private final A a; // c'tor injected
public int bar() {
return a.foo(Integer::parseInt);
}
}
现在假设我想为B编写单元测试:
@Test
public void test() {
A a = mock(A.class);
B b = new B(a);
b.bar();
verify(a).foo(Integer::parseInt);
}
问题是测试失败,因为方法引用不相等。
答案 0 :(得分:12)
Lambda不会被缓存,这似乎是故意的。没有办法比较两个lambdas,看看他们是否会做同样的事情。
您需要执行类似
的操作static final Function<String, Integer> parseInt = Integer::parseInt;
@Test
public void test() {
Function<String, Integer> foo = parseInt;
Function<String, Integer> bar = parseInt;
assertThat(foo, equalTo(bar));
}
Brian Goetz的回答; Is there a way to compare lambdas?
答案 1 :(得分:4)
我手头没有API,但Function是一个界面。 Integer :: parseInt似乎没有缓存,因此它将返回两个不同的实例,这些实例将通过reference =&gt;进行比较。假的。
你可以通过写一个比较器来完成它,它可以做你想要的。
答案 2 :(得分:1)
查看Java语言规范:
15.27.4. Run-time Evaluation of Lambda Expressions
在运行时,lambda表达式的计算类似于类实例创建表达式的计算,只要正常完成产生对对象的引用即可。 lambda表达式的评估不同于lambda体的执行。
分配并初始化具有以下属性的类的新实例,或者引用具有以下属性的类的现有实例。
...
这些规则旨在为Java编程语言的实现提供灵活性,其中包括:
的的
不需要在每次评估时分配新对象。
由不同的lambda表达式生成的对象不必属于不同的类(例如,如果主体是相同的)。
评估产生的每个对象都不必属于同一个类(例如,可能内联捕获的局部变量)。
如果“现有实例”可用,则无需在先前的lambda评估中创建它(它可能是在封闭类中分配的)初始化,例如)。
原则上,这意味着即使在源代码中单次出现Integer::parseInt
,在多次评估时也可能导致不同的对象实例(甚至是不同的类),而不是多次出现它。确切的决定留给实际的JRE实现。请参阅this answer,讨论Oracle实施的当前行为。
答案 3 :(得分:0)
测试没有通过是可以的。 Lambda不是对象,它们不受对象标识等属性的约束。相反,它们是功能接口的特殊实现。
我相信您不应期望您的代码依赖于您所描述的行为。