为什么不能 Java 对这段代码进行类型检查?

Why can't Java typecheck this code?

我有一些流处理代码,它接受单词流并对它们执行一些操作,然后将它们缩减为 Map,其中包含单词作为键,单词出现的次数作为 Long值。为了代码的简洁,我使用了jOOL library's Seqclass,里面包含了一些有用的快捷方式

如果我这样写,代码编译得很好:

item.setWordIndex (
        getWords (item)                      // returns a Seq<String>
              .map (this::removePunctuation) // String -> String
              .map (stemmer::stem)           // String -> String
              .groupBy(str -> str, Collectors.counting ()));

但是,如果我尝试用更自记录的 Function::identity 替换 str -> str lambda,我会收到以下错误:

The method setWordIndex(Map<String,Long>) in the type MyClass is not applicable for the arguments (Map<Object,Long>)
The type Function does not define identity(String) that is applicable here

为什么 Function::identity 的行为与 str -> str 有任何不同,我(也许天真地)假设它是直接等效的,为什么编译器在使用时不能处理它?

(是的,我知道我可以通过将之前的 map 应用程序移动到 groupBy 操作中来删除身份函数,但我发现这样的代码更清晰,因为它遵循更直接的应用程序逻辑)

两种类型之间存在细微差别;它们并不直接等价:

  • Function.identity() 必须 return 输入类型,因为它的类型是 Function<T, T>;
  • str -> str 可以 return 更宽的类型;实际上它是 Function<? extends T, T>.

你想要Function.identity()(returns一个Function<T, T>),而不是Function::identity(匹配SAM类型Supplier<Function<T, T>>)。

以下代码可以正常编译:

static String removePunctuation(String x) { return x; }
static String stem(String x) { return x; }

// ...

final Map<String, Long> yeah = Seq.of("a", "b", "c")
        .map(Test::removePunctuation)
        .map(Test::stem)
        .groupBy(Function.identity(), Collectors.counting());