两个确切的方法引用不相等
Two exact method references are not equal
以下测试失败
@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);
}
问题是测试失败,因为方法引用不相等。
我手边没有 API,但是 Function 是一个接口。 Integer::parseInt 好像没有缓存,所以会 return 两个不同的实例,通过引用比较 => false.
你可以写一个比较器让它通过,它会做你想做的事。
Lambda 没有被缓存,这似乎是故意的。无法比较两个 lambda 以查看它们是否会做同样的事情。
你需要做类似的事情
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?
考试没通过也没关系。 Lambda 不是对象,它们不受对象标识等属性的约束。相反,它们是功能接口的临时实现。
我相信您不应该期望您的代码依赖于您所描述的行为。
查看 Java 语言规范:
15.27.4. Run-time Evaluation of Lambda Expressions
At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a lambda expression is distinct from execution of the lambda body.
Either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.
…
These rules are meant to offer flexibility to implementations of the Java programming language, in that:
A new object need not be allocated on every evaluation.
Objects produced by different lambda expressions need not belong to different classes (if the bodies are identical, for example).
Every object produced by evaluation need not belong to the same class (captured local variables might be inlined, for example).
If an "existing instance" is available, it need not have been created at a previous lambda evaluation (it might have been allocated during the enclosing class's initialization, for example).
原则上,这意味着即使在您的源代码中出现一次Integer::parseInt
,在多次评估时也可能导致不同的对象实例(甚至是不同的类),更不用说它的多次出现。确切的决定留给实际的 JRE 实现。请参阅 this answer 讨论 Oracle 实施的当前行为。
以下测试失败
@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);
}
问题是测试失败,因为方法引用不相等。
我手边没有 API,但是 Function 是一个接口。 Integer::parseInt 好像没有缓存,所以会 return 两个不同的实例,通过引用比较 => false.
你可以写一个比较器让它通过,它会做你想做的事。
Lambda 没有被缓存,这似乎是故意的。无法比较两个 lambda 以查看它们是否会做同样的事情。
你需要做类似的事情
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?
考试没通过也没关系。 Lambda 不是对象,它们不受对象标识等属性的约束。相反,它们是功能接口的临时实现。
我相信您不应该期望您的代码依赖于您所描述的行为。
查看 Java 语言规范:
15.27.4. Run-time Evaluation of Lambda Expressions
At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a lambda expression is distinct from execution of the lambda body.
Either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.
…
These rules are meant to offer flexibility to implementations of the Java programming language, in that:
A new object need not be allocated on every evaluation.
Objects produced by different lambda expressions need not belong to different classes (if the bodies are identical, for example).
Every object produced by evaluation need not belong to the same class (captured local variables might be inlined, for example).
If an "existing instance" is available, it need not have been created at a previous lambda evaluation (it might have been allocated during the enclosing class's initialization, for example).
原则上,这意味着即使在您的源代码中出现一次Integer::parseInt
,在多次评估时也可能导致不同的对象实例(甚至是不同的类),更不用说它的多次出现。确切的决定留给实际的 JRE 实现。请参阅 this answer 讨论 Oracle 实施的当前行为。