Java 泛型类型推断不起作用时如何编译代码?

How to make code compile when Java generic type inference not working?

我正在使用 Java 流 API 来合并多个地图。

逻辑是这样的:{1:a,2:b} + {1:b,3:c} = {1:[a,b],2:[b],3:[c ]}

我将地图扁平化为 K-V 对,并使用 "group by key" 收集结果。结果类型为 Map<Key,List<Value>>

    List<Map<Key, Value>> maps = ....;
    maps.stream().flatMap(s->s.entrySet().stream()).collect(
        groupingBy(e -> e.getKey(), 
            mapping(e -> e.getValue(),  toList())
        )
    );

上面的代码没问题。

然后我想对结果映射的每个值应用一些操作。举个简单的例子,让 [a,b] 变成 "ab"。所以我添加了 collectingAndThen 以对它们应用转换 x->x

    List<Map<Key, Value>> maps = ....;
    maps.stream().flatMap(s->s.entrySet().stream()).collect(
        groupingBy(e -> e.getKey(), 
            mapping(e -> e.getValue(),  collectingAndThen(toList(),x->x))
        )
    );

并且上面的代码不会使用 eclipse JDT 进行编译说 "Type mismatch: cannot convert from List<Value> to List<Object>"

如果我将简单的 x-x 更改为 "real one" x->transformValue(x) 更多错误消息出现在 e -> e.getKey()e -> e.getValue():

The method getKey() is undefined for the type Object
The method getValue() is undefined for the type Object
The method transformValue(List<Value>) in the type 
Sometype is not applicable for the arguments (List<Object>)

我该如何解决这个问题?有什么方法可以告诉编译器 toList() -- public static <T> Collector<T, ?, List<T>> toList() 中的 <T> 是 class Value 而不是 Object?谢谢。

编辑:

正如 Stephan Herrmann 在评论中所说,这是 Eclipse JDT 的一个错误 http://bugs.eclipse.org/489976,将在 4.6 中修复。

你的代码编译对我来说没有错误,但我使用的是 IntelliJ 而不是 Eclipse。

要显式指定 toList() 的类型参数,请使用 Collectors.<Value>toList() 调用它。

collectingAndThen 使用的函数添加强制转换,例如.. (List<Value> x) x->x,并使其成为:

List<Map<Key, Value>> maps = ....;
maps.stream().flatMap(s->s.entrySet().stream()).collect(
    groupingBy(e -> e.getKey(), 
        mapping(e -> e.getValue(),  collectingAndThen(toList(),(List<Value> x) x->x))
    )
);

当它进入 collectingAndThen 时,它推断它应该是一个返回 List<Object> 的函数,它与预期的 List<Value>...

不匹配

如果您看到这样的问题,一个有用的做法是从 lambda shorthand 恢复为完整函数,并查看它是否 使用显式类型进行编译,例如:

Function<List<Value>, List<Value>> f = new Function<List<Value>, List<Value>>() {
    @Override
    public List<Value> apply(List<Value> x) {
        return x;
    }
};

另一个提示是,在 Stream Fluent API 中,可能会有很多类型推断,其中一些可能不是您所期望的...