4

我正在尝试编写一些代码来接收java.util.function.*包中类的各种实现,但是对于我真正想要解决的特定语法,我一直在针对某个编译器错误运行(像obj.<Type>foo(/*...*/)工作一样的显式类型参数,但它们缺乏恩典)。

简而言之,我希望能够始终尽可能使用方法引用,但出于某种原因,我不明白为什么编译器无法理解下面解释的引用。

假设有以下两个类(实现无关):

一些具有 getter/setter 方法的实体类:

class Thing {
  public List<String> getThings() {
    return null;
  }

  public void setThings(List<String> things) {
  // ...
  }
}

对该实体类的实例执行操作的其他一些类:

class FooBar<A> {
  public <B> void foo(Function<A, List<B>> f) {
    // ...
  }

  public <B> void bar(BiConsumer<A, List<B>> f) {
    // ...
  }

  public <B> void wuz(Function<A, List<B>> x, BiConsumer<A, List<B>> y) {
    // ...
  }
}

在执行对这些方法的调用时,编译器会给我各种错误:

// create an instance of the handler class
FooBar<Thing> fb = new FooBar<>();

前任。1)调用期望函数的方法工作得很好,没有编译错误:

fb.foo(Thing::getThings);

前任。2)然而调用期望双消费者的方法给了我这个:

fb.bar(Thing::setThings);
// The type Thing does not define setThings(Thing, List<B>) that is applicable here

前任。3)正如预期的那样,明确说明类型工作得很好,没有编译错误:

fb.<String>bar(Thing::setThings);

前任。4)然而,当我写出 lambda 时,它给了我一个不同的编译错误(虽然在 lambda 参数中说明类型可以正常工作):

fb.bar((thing, things) -> thing.setThings(things));
// The method setThings(List<String>) in the type Thing is not applicable for the arguments (List<Object>)

前任。5)当调用期望两者的方法时,每个参数都会出现不同的编译错误:

fb.wuz(
  Thing::getThings,
  // The type of getThings() from the type Thing is List<String>, this is incompatible with the descriptor's return type: List<B>

  Thing::setThings
  // The type Thing does not define setThings(Thing, List<B>) that is applicable here
);

前任。6)再次,正如预期的那样,明确说明类型再次正常工作,没有编译错误:

fb.<String>wuz(Thing::getThings, Thing::setThings);

前任。7)这是最让我感到困惑的:对于同时需要函数和 biconsumer 的方法,写出 biconsumer(无类型)并使用函数的方法引用,工作正常,没有编译错误(?!) :

fb.wuz(Thing::getThings, (thing, things) -> thing.setThings(things));

我不明白的是,编译器在不同场景中确定运行时类型/类型擦除时,显然会以不同方式处理显式 lambda 和方法引用,即:

  1. 获取参数并返回值的函数式接口
  2. 获取参数但不返回值的函数式接口
  3. 带有 1. 和 2. 类型参数的方法

这似乎只发生在函数接口的类型本身是泛型类型(在本例中为 List)时,这让我相信这与类型擦除有关,但我对回答。

我很想能够写...

fb.wuz(Thing::getThings, Thing::setThings);

...没有显式类型或普通 lambda 表达式。

如果有办法重构方法FooBar来支持这一点,我真的很想知道。

当然,如果有人能够解释编译器的这些不同行为,我也会非常感激!:-)

编辑

我特别有兴趣了解为什么示例 #1 和 #7确实有效,但为什么示例 #4 本身不起作用(然后,为什么示例 #2 也不起作用)。

4

1 回答 1

1

提出的问题实际上似乎不是编译错误,而是 Eclipse 编辑器中的错误。出现错误的 Eclipse 版本是 Luna EE 4.4.0。更新到 Luna EE 4.4.2 后,编辑器的行为符合我的预期(以及 Java 编译器的行为方式已经如此)。

于 2015-03-24T19:16:02.373 回答