我正在使用3d派对库,他们返回缺少类型规范的集合(例如public List getFoo();
),并且我正在尝试转换其返回类型并返回具有适当类型的列表。
我创建了一个演示问题的简单示例。 e.g。
编辑原始问题将l2声明为ArrayList
而非List
,现在已更正。
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
public class Foo {
public static void main(String[] args) {
ArrayList l = new ArrayList();
l.add(1);
l.add(2);
List<String> l2 = l.stream().map(Object::toString).collect(Collectors.toList());
}
}
这无法编译。
$ javac Foo.java
Foo.java:10: error: incompatible types: Object cannot be converted to List<String>
List<String> l2 = l.stream().map(Object::toString).collect(Collectors.toList());
^
1 error
如果我稍微修改程序以便编译,我可以检查流/收集操作的返回类型。虽然我不得不施展结果,但它“有效”。
e.g。
import java.util.ArrayList;
import java.util.stream.Collectors;
public class Foo {
public static void main(String[] args) {
ArrayList l = new ArrayList();
l.add(1);
l.add(2);
Object l2 = l.stream().map(Object::toString).collect(Collectors.toList());
System.out.println(l2.getClass());
}
}
运行此节目......
$ javac Foo.java
Note: Foo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ java Foo
class java.util.ArrayList
正如所料。
因此,Collectors.listCollector()在运行时做了正确的事情,但这是预期的编译时行为吗?如果是这样,它周围是否有“适当”的方式?
答案 0 :(得分:20)
stream()
,map()
,collect()
和所有其他流方法都依赖于通用类型来使事情顺利运行。如果使用原始类型作为输入,则所有泛型都将被删除,并且所有内容都将变为原始类型。例如,如果您有List<String>
,则调用stream()
方法会为您提供类型为Stream<String>
的对象。
但是如果您从原始类型List
开始,那么调用stream()
会为您提供原始类型Stream
的对象。
map()
方法有这个声明:
<R> Stream<R> map(Function<? super T,? extends R> mapper)
但是因为它是在原始Stream
上调用的,就好像声明是
Stream map(Function mapper)
因此调用map()
的结果只是Stream
。 collect()
的签名中填充了泛型:
<R> R collect(Supplier<R> supplier,
BiConsumer<R,? super T> accumulator,
BiConsumer<R,R> combiner)
使用原始类型调用时,它将被删除为
Object collect(Supplier supplier,
BiConsumer accumulator,
BiConsumer combiner)
所以当流源是原始类型时,流管道的返回类型为Object
。显然这与ArrayList<String>
不兼容,并且您收到编译错误。
要解决此问题,请尽快将您的类型带入通用世界。这可能涉及未经检查的强制转换,您应该抑制警告。当然,只有在您确定返回的集合包含仅具有预期类型的对象时才执行此操作。
此外,正如Hank D指出的那样,toList()
收集器返回List
,而不是ArrayList
。您可以将返回值分配给List
类型的变量,也可以使用toCollection()
显式创建ArrayList
的实例。
以下是包含以下修改的代码:
@SuppressWarnings("unchecked")
ArrayList<Integer> l = (ArrayList<Integer>)getRawArrayList();
l.add(1);
l.add(2);
ArrayList<String> l2 = l.stream()
.map(Object::toString)
.collect(Collectors.toCollection(ArrayList::new));
答案 1 :(得分:3)
Collectors.toList()返回List,而不是ArrayList。这将编译:
public static void main(String[] args) {
ArrayList<?> l = getRawArrayList();
List<String> l2 = l.stream().map(Object::toString).collect(Collectors.toList());
}