简体   繁体   English

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

[英]Generic type mismatch while using a Collector returned by the method - Java 17

I was experimenting with records and streams .我正在试验recordsstreams

I've created these records to count the number of letters in a text.我创建了这些记录来计算文本中的字母数。

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);
    }
}

And here is the snippet where they're used:这是使用它们的片段:

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
        ));

The snippet shown above doesn't produce error if I comment out collectingAndThen() to be used as the downstream collector within the groupingBy() .如果我注释掉collectingAndThen()用作groupingBy()中的下游收集器,上面显示的代码片段不会产生错误。

However, the compiler gets lost when I'm trying to use LetterCount.countingLetters() as the downstream collector.但是,当我尝试使用LetterCount.countingLetters()作为下游收集器时,编译器会丢失。

I'm getting the following error message:我收到以下错误消息:

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

Interface Collector has the following declaration:接口Collector具有以下声明:

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

Where the second generic type parameter A denotes the type of the mutable container which is used internally to accumulate the results of the reduction.其中第二个泛型类型参数A表示可变容器的类型,该容器在内部用于累积归约结果。 This type is usually hidden by the implementations.这种类型通常被实现隐藏。

Your method countingLetters() declares the return type as follows:您的方法countingLetters()声明返回类型如下:

Collector<Letter, Object, LetterCount>

And that implies the type of the mutable container of the collector returned by this method is expected to be an Object .这意味着此方法返回的收集器的可变容器类型应为Object

Reminder: generics are invariant , ie if you've said Object you have to provide only Object (not it's subtype, not unknown type ? , only the Object type itself).提醒: generics 是不变的,即如果你说Object你必须只提供Object (不是它的子类型,不是未知类型? ,只有Object类型本身)。

And that is incorrect for several reasons:由于以下几个原因,这是不正确的:

  • All collectors built-in in the JDK are hiding their types of mutable containers. JDK 中内置的所有收集器都隐藏了它们的可变容器类型。 Collector conting that you are using in your code declares to return Collector<T,?,Long> .您在代码中使用的收集器条件声明返回conting Collector<T,?,Long> Under the hood, it makes use of summingLong , which in turn returns Collector<T,?,Long> although it internally utilizes long[] as a container .在引擎盖下,它使用summingLong ,它反过来返回Collector<T,?,Long>尽管它在内部使用long[]作为container That is because it doesn't make sense to expose these implementation details.那是因为公开这些实现细节没有意义。 And as a consequence, generic parameters of the return type you've declared doesn't conform to the generic parameters of the collector that you are returning.因此,您声明的返回类型的通用参数不符合您要返回的收集器的通用参数。 Ie since you are given an unknown type ?即因为你被赋予了未知类型? , you can't declare to return an Object . ,您不能声明返回Object

  • Even if you wouldn't use built-in collectors, but your own custom collector instead, it still will not be a very bright idea to expose the actual type of its container .即使您不使用内置收集器,而是使用您自己的自定义收集器,公开其容器实际类型仍然不是一个好主意。 Simply because sometime in the future, you might want to change it.仅仅是因为在未来的某个时候,您可能想要更改它。

  • Object class is immutable, hence it's fruitless to use it as a container type ( if you would try to implement a custom collector ) because it is not capable to accumulate data. Object class 是不可变的,因此将其用作容器类型(如果您尝试实现自定义收集器)是徒劳的,因为它无法累积数据。


The bottom line: the second generic parameter in the collector returned by the countingLetters() method isn't correct.底线: countingLetters()方法返回的收集器中的第二个通用参数不正确。

To fix it, you have to change the type of the mutable container to be either:要修复它,您必须将可变容器的类型更改为:

  • an unknown type ?未知类型? which encompasses all possible types, ie expected that provided collector may have a mutable container of any type (and that's how all collectors in the JDK have been declared);它包含所有可能的类型,即预期提供的收集器可能具有任何类型的可变容器(这就是 JDK 中所有收集器的声明方式);
  • or to an upper bounded wildcard ? extends Object或上界通配符? extends Object ? extends Object (which is basically a more verbose way to describe the unknown type ). ? extends Object (这基本上是描述未知类型的更详细的方式)。
public static Collector<Letter, ?, LetterCount> countingLetters()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM