我有一个数据对象列表,我需要以各种方式对其进行分组,然后对分组结果执行常见操作。所以我试图将常用操作提取到单个方法,如下面的设计示例所示:
private static void print(List<Integer> data,
Collector<Integer, ?, Map<?, List<Integer>>> collector) {
data.stream().collect(collector)
.forEach((key, list) -> System.out.println(key + ": " + list));
}
private static void printByMagnitude() {
List<Integer> data = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
print(data, Collectors.<Integer,String>groupingBy(i -> i < 5 ? "small" : "large"));
}
private static void printByModulus() {
List<Integer> data = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
print(data, Collectors.<Integer,Integer>groupingBy(i -> i % 2));
}
请注意,在print
方法中,收集器的结果类型是Map
,其中包含未知密钥Map<?, List<Integer>>
,因为当我按幅度打印时,我使用String
个密钥,当我按模数打印时,我使用Integer
个键。
此代码在两次调用Collectors.groupingBy
时都会产生两个编译错误。第一个抱怨使用String
键进行通话:
Error:(19, 58) java: incompatible types:
java.util.stream.Collector<java.lang.Integer,capture#1 of ?,
java.util.Map<java.lang.String,java.util.List<java.lang.Integer>>>
cannot be converted to
java.util.stream.Collector<java.lang.Integer,?,
java.util.Map<?,java.util.List<java.lang.Integer>>>
第二个抱怨使用Integer
键进行通话:
Error:(24, 59) java: incompatible types:
java.util.stream.Collector<java.lang.Integer,capture#2 of ?,
java.util.Map<java.lang.Integer,java.util.List<java.lang.Integer>>>
cannot be converted to
java.util.stream.Collector<java.lang.Integer,?,
java.util.Map<?,java.util.List<java.lang.Integer>>>
Collectors.groupingBy
的返回类型为<T, K> Collector<T, ?, Map<K, List<T>>>
,因此在Magnitude
和Modulus
情况下,这应该是
Collector<Integer, ?, Map<String,List<Integer>>>
Collector<Integer, ?, Map<Integer,List<Integer>>>
分别
为什么这些不匹配print
中的收集器参数,
Collector<Integer, ?, Map<?, List<Integer>>> collector
答案 0 :(得分:1)
使用更简单的示例进行说明,如果您使用方法foo(Number)
,则可以传入Integer
,因为Integer
是Number
的子类型。但是,如果您使用方法foo(List<Number>)
,则无法传递List<Integer>
,因为List<Integer>
不是List<Number>
的子类型。
但如果您的方法foo
只想从Number
检索List
,您可以将签名更改为foo(List<? extends Number>)
(另请参阅“What is PECS”) ,允许列表使用Number
的子类型进行参数化。 List<Integer>
是List<? extends Number>
更复杂的是,Map<Integer,List<Integer>>
和Map<String,List<Integer>>
都是Map<?,List<Integer>>
的子类型,但Collector< … Map<Integer,List<Integer>> >
和Collector< … Map<String,List<Integer>> >
不是 Collector< … Map<?,List<Integer>> >
的子类型。
解决方案是一样的。您希望从Collector
检索地图,因此您必须求助于“? extends …
”,即使用Collector<Integer, ?, ? extends Map<?, List<Integer>>>
类型:
private static void print(List<Integer> data,
Collector<Integer, ?, ? extends Map<?, List<Integer>>> collector) {
data.stream().collect(collector)
.forEach((key, list) -> System.out.println(key + ": " + list));
}
private static void printByMagnitude() {
List<Integer> data = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
print(data, Collectors.<Integer,String>groupingBy(i -> i < 5 ? "small" : "large"));
}
private static void printByModulus() {
List<Integer> data = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
print(data, Collectors.<Integer,Integer>groupingBy(i -> i % 2));
}
答案 1 :(得分:0)
只需写一下:
private static <T, U> void print(List<T> data,
Collector<T, ?, Map<U, List<T>>> collector) {
data.stream().collect(collector)
.forEach((key, list) -> System.out.println(key + ": " + list));
}
private static void printByMagnitude() {
List<Integer> data = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
print(data, Collectors.<Integer, String>groupingBy(i -> i < 5 ? "small" : "large"));
}
private static void printByModulus() {
List<Integer> data = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
print(data, Collectors.<Integer, Integer>groupingBy(i -> i % 2));
}
这里的不同之处在于我用通用参数替换了无界通配符类型(&#39; ?
&#39;字符)(我使打印方法通用)。最大的区别在于?
&#39;无界通配符代表 one type
的某些东西不是 any type
。由于你有两种类型的东西(整数和字符串),编译器抱怨。
另请注意,您并不需要使用参数调用泛型方法(我认为从Java 7开始)。您也可以简单地写一下:
private static <T, U> void print(List<T> data,
Collector<T, ?, Map<U, List<T>>> collector) {
data.stream().collect(collector)
.forEach((key, list) -> System.out.println(key + ": " + list));
}
private static void printByMagnitude() {
List<Integer> data = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
print(data, Collectors.groupingBy(i -> i < 5 ? "small" : "large"));
}
private static void printByModulus() {
List<Integer> data = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
print(data, Collectors.groupingBy(i -> i % 2));
}
答案 2 :(得分:0)
简单地替换
private static <A, B> void print(List<Integer> data, Collector<Integer, ?, Map<A, List<B>>> groupingBy) {
data.stream().collect(groupingBy).forEach((key, value) -> System.out.println(key + " : " + value));
}
与
private static void print(List<Integer> data,
Collector<Integer, ?, Map<?, List<Integer>>> collector) {
data.stream().collect(collector)
.forEach((key, list) -> System.out.println(key + ": " + list));
}
<强>为什么吗
由于
?
仅适用于Object
类,仅适用于其子类
即
AnyType<?> object=new AnyType<Object> // true
AnyType<?> object=new AnyType<Number> // since Number is subchild of Object but Still false
编辑:
在您的方法printByModulus()
中传递Collectors.<Integer, Integer>
而在方法printByMagnitude()
中传递Collectors.<Integer, String>
是导致错误的唯一原因。