两个确切的方法引用不相等

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 实施的当前行为。