java - 使用方法返回的收集器时通用类型不匹配 - Java 17

标签 java generics java-stream collectors java-17

我正在尝试使用记录

我创建了这些记录来计算文本中的字母数量。

record Letter(int code) {
    Letter(int code) {
        this.code = Character.toLowerCase(code);
    }
}

record LetterCount(long count) implements Comparable<LetterCount> {
    @Override
    public int compareTo(LetterCount other) {
        return Long.compare(this.count, other.count);
    }

    static Collector<Letter, Object, LetterCount> countingLetters() {
        return Collectors.collectingAndThen(
            Collectors.<Letter>counting(), 
            LetterCount::new);
    }
}

这是使用它们的代码片段:

final var countedChars = text.chars()
    .mapToObj(Letter::new)
    .collect(
        groupingBy(Function.identity(), 
            LetterCount.countingLetters()                      // compilation error
            // collectingAndThen(counting(), LetterCount::new) // this line doesn't produce error
        ));

如果我注释掉 collectingAndThen() 以用作 groupingBy() 中的下游收集器,上面显示的代码片段不会产生错误。

但是,当我尝试使用 LetterCount.countingLetters() 作为下游收集器时,编译器会丢失。

我收到以下错误消息:

Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
        Collector cannot be resolved to a type
        Type mismatch: cannot convert from Collector<Letter,capture#17-of ?,LetterCount> to Collector<Letter,Object,LetterCount>
        The method countingLetters() from the type LetterCount refers to the missing type Collector
        The method entrySet() is undefined for the type Object

最佳答案

界面 Collector 有以下声明:

public interface Collector<T,​A,​R>

其中第二个泛型类型参数 A表示可变容器的类型,该容器在内部用于累积归约结果。这种类型通常被实现隐藏。

你的方法countingLetters()声明返回类型如下:

Collector<Letter, Object, LetterCount>

这意味着此方法返回的收集器的可变容器的类型预计为 Object .

提醒:泛型是不变的,即如果您说过 Object您只需提供 Object (不是它的子类型,不是未知类型 ?,只有 Object 类型本身)。

由于以下几个原因,这是不正确的:

  • JDK 中内置的所有收集器都隐藏了其可变容器的类型。 Collection 家conting您在代码中使用的声明返回 Collector<T,?,Long> 。在幕后,它利用 summingLong ,这又返回 Collector<T,?,Long>尽管它内部使用 long[]作为一个容器。这是因为公开这些实现细节是没有意义的。因此,您声明的返回类型的泛型参数不符合您返回的收集器的泛型参数。 IE。因为你得到了一个未知的类型 ? ,您不能声明返回 Object .

  • 即使您不使用内置收集器,而是使用您自己的自定义收集器,暴露实际类型仍然不是一个非常聪明的主意容器。只是因为在将来的某个时候,您可能想要更改它。

  • Object类是不可变的,因此将其用作容器类型是徒劳的(如果您尝试实现自定义收集器),因为它无法累积数据。


底线:countingLetters()返回的收集器中的第二个通用参数方法不正确。

要修复此问题,您必须将可变容器的类型更改为:

  • 未知类型 ?它包含所有可能的类型,即期望提供的收集器可能有任何类型的可变容器(这就是 JDK 中所有收集器的声明方式);
  • 或上限通配符 ? extends Object (这基本上是描述未知类型的更详细的方式)。
public static Collector<Letter, ?, LetterCount> countingLetters()

关于java - 使用方法返回的收集器时通用类型不匹配 - Java 17,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71982217/

相关文章:

java - 查找多个键是否映射到相同的值

java - 将对象从 Activity 传递到 IntentService

c# - 我如何解决 C# 对泛型类型调用静态函数的限制

Java Streams -> 从 List<List<String>> 中提取特定索引处的值

Java JButton 只有图像?

java - Spring 3.0 Expression Langugage Java 泛型参数

java - 如何在我的 Java 方法中拥有两种不同的返回类型?

java - 二维坐标上的流/IntRange?

java 8更改列表以使用列表实例进行映射

java - 使用正则表达式以任何顺序查找单词列表的子段