Java Stream Collect() 分类器无法检测类型

pan*_*low 6 java collections java-stream

我有以下代码从文本文件读取行:

try (BufferedReader br = new BufferedReader(new InputStreamReader(Uio.decodeFrom(url)))) {
        return br.lines()
                .parallel()
                .map(s -> s.split("\\s+")) // split by whitespace
                .collect(
                        Collectors.groupingByConcurrent(
                                arr -> arr[0], // String 1
                                Collectors.groupingByConcurrent(
                                        arr -> arr[arr.length-1], // String 2
                                        Collectors.counting()
                                )
                        )
                );
    } catch (IOException e) {
        throw new UncheckedIOException(e);
    }
Run Code Online (Sandbox Code Playgroud)

文本文件包含如下数据

String1     ... cols      ... String2
string1data ... otherdata ... string2data
...
Run Code Online (Sandbox Code Playgroud)

我正在尝试按 和 进行分组String1String2获取它们的计数。那么最终结果应该是一个Map<String, Map<String, Long>>. 然而,对于上面的代码,编译器说返回collect()一个 ConcurrentMap <Object, ConcurrentMap<Object, Long>>.

为什么键不是字符串?

rge*_*man 2

String我可以复制此错误消息,但错误消息中的替换Object似乎是转移注意力。真正的问题是Java 的泛型是不变的。

如果对的调用collect返回 a ,则即使 a是 a ,ConcurrentMap<String, ConcurrentMap<String, Long>>也不匹配。内部类型必须完全匹配,没有通配符和边界。Map<String, Map<String, Long>>ConcurrentMapMapMap

如果您向返回类型引入上限通配符,它​​将编译而不会出现错误。让它返回 type Map<String, ? extends Map<String, Long>>,以便内部ConcurrentMap<String, Long>匹配。

返回类型Map<String, ConcurrentMap<String, Long>>也可以工作。

目前还不清楚为什么String在解决泛型不变问题之前没有被捕获。只是猜测:编译器尚未捕获String,因为它首先发现了不变泛型问题。一旦解决了不变泛型问题,它就可以正确编译,这意味着确实String可以推断出来。