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 中,可能会有很多类型推断,其中一些可能不是您所期望的...
我正在使用 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 中,可能会有很多类型推断,其中一些可能不是您所期望的...