收集器与结果类型中的通配符不匹配
Collector doesn't match wildcard in result type
我有一个数据对象列表,需要以各种方式对其进行分组,然后对分组结果执行常见操作。因此,我试图将常用操作提取到单个方法中,如以下人为设计的示例所示:
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<?, List<Integer>>
的 Map
,因为当我按幅度打印时,我使用 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
的 return 类型是 <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
?
简单写一下:
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));
}
这里的区别是我用通用参数替换了无限通配符类型('?
'字符)(我使打印方法通用)。最大的区别是'?
'无限通配符类型代表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));
}
只需替换
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
Class ,甚至不适用于其子项 类
即
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>
是您出错的唯一原因。
用一个更简单的例子来解释,如果你有一个方法foo(Number)
,你可以传入一个Integer
,因为Integer
是Number
的子类型。但是,如果你有一个方法foo(List<Number>)
,你不能传入一个List<Integer>
,因为List<Integer>
不是List<Number>
的子类型。
但是,如果您的方法 foo
只想从 List
中检索 Number
,您可以将签名更改为 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));
}
我有一个数据对象列表,需要以各种方式对其进行分组,然后对分组结果执行常见操作。因此,我试图将常用操作提取到单个方法中,如以下人为设计的示例所示:
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<?, List<Integer>>
的 Map
,因为当我按幅度打印时,我使用 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
的 return 类型是 <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
?
简单写一下:
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));
}
这里的区别是我用通用参数替换了无限通配符类型('?
'字符)(我使打印方法通用)。最大的区别是'?
'无限通配符类型代表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));
}
只需替换
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
Class ,甚至不适用于其子项 类
即
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>
是您出错的唯一原因。
用一个更简单的例子来解释,如果你有一个方法foo(Number)
,你可以传入一个Integer
,因为Integer
是Number
的子类型。但是,如果你有一个方法foo(List<Number>)
,你不能传入一个List<Integer>
,因为List<Integer>
不是List<Number>
的子类型。
但是,如果您的方法 foo
只想从 List
中检索 Number
,您可以将签名更改为 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));
}