为什么这个 java 8 流操作评估为 Object 而不是 List<Object>?还是只是列表? [英] Why does this java 8 stream operation evaluate to Object instead of List&lt;Object&gt; or just List?

查看:14
本文介绍了为什么这个 java 8 流操作评估为 Object 而不是 List<Object>?还是只是列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一个 3d 方库,它们返回缺少类型规范的集合(例如 public List getFoo();),我正在尝试转换它们的返回类型并返回具有适当类型的列表.

I'm working with a 3d party library, and they return Collections that lack type specifications (e.g. public List getFoo();) , and I'm trying to convert their return types and return a list with a proper type.

我创建了一个简单的例子来演示这个问题.例如

I have created a simple example that demonstrates the problem. e.g.

edit 原始问题将 l2 声明为 ArrayList 而不是 List,现在已更正.

edit The original question declared l2 as an ArrayList rather than a List, that is corrected now.

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

如果我稍微修改程序使其编译,我可以检查流/收集操作的返回类型.它有效",尽管我必须投射结果.

If I modify the program slightly so it compiles and I can check the return type of the stream/collect operation. It "works", although I'd have to cast the result.

例如

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() 在运行时做了正确的事情,但是这种编译时行为是预期的吗?如果是这样,是否有适当"的方法来解决它?

So, Collectors.listCollector() does the right thing at runtime, but is this compile time behavior expected? If so, is there a "proper" way around it?

推荐答案

stream(), map(), collect(),所有其他流方法都依赖于泛型类型才能正常工作.如果您使用原始类型作为输入,那么所有泛型都将被删除,并且一切都变成原始类型.例如,如果您有一个 List,调用 stream() 方法会给您一个 Stream 类型的对象.

The stream(), map(), collect(), and all the other stream methods rely on generic typing for things to work well. If you use a raw type as input, then all the generics are erased, and everything turns into a raw type. For example, if you have a List<String>, calling the stream() method gives you an object of type Stream<String>.

但是如果您从原始类型 List 开始,那么调用 stream() 会为您提供原始类型 Stream 的对象.

But if you start out with a raw type List, then calling stream() gives you an object of the raw type Stream instead.

map() 方法有这样的声明:

    <R> Stream<R> map(Function<? super T,? extends R> mapper)

但是由于它是在原始 Stream 上调用的,就好像声明是

but since it's called on a raw Stream, it's as if the declaration is

    Stream map(Function mapper)

所以调用map() 的结果只是一个Stream.collect() 的签名用泛型填充:

so the result of calling map() is simply a Stream. The signature of collect() is filled with generics:

    <R> R collect(Supplier<R> supplier,
                  BiConsumer<R,? super T> accumulator,
                  BiConsumer<R,R> combiner)

当使用原始类型调用时,它会被擦除

When called with a raw type, it gets erased to

    Object collect(Supplier supplier,
                   BiConsumer accumulator,
                   BiConsumer combiner)

所以当它的源是原始类型时,流管道的返回类型是 Object.显然这与 ArrayList 不兼容,你会得到一个编译错误.

so the return type of your stream pipeline is Object when its source is a raw type. Obviously this isn't compatible with ArrayList<String> and you get a compilation error.

要解决此问题,请尽快将您的类型带入泛型世界.这可能涉及未经检查的强制转换,您可能应该取消警告.当然,只有在您确定返回的集合仅包含预期类型的​​对象时才执行此操作.

To fix this, bring your types into the generic world as soon as possible. This will probably involve unchecked casts, and you should probably suppress the warning. Of course, do this only if you're sure the returned collection contains objects only of the expected type.

此外,正如 Hank D 指出的那样,toList() 收集器返回一个List,而不是 ArrayList.您可以将返回值分配给 List 类型的变量,也可以使用 toCollection() 显式创建 ArrayList 的实例.

In addition, as Hank D pointed out, the toList() collector returns a List, not an ArrayList. You can either assign the return value to a variable of type List, or you can use toCollection() to create an instance of ArrayList explicitly.

这是包含这些修改的代码:

Here's the code with these modifications included:

    @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));

这篇关于为什么这个 java 8 流操作评估为 Object 而不是 List<Object>?还是只是列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆