为什么这个 java 8 流操作计算结果为 Object 而不是 List 或只是 List?
2024-01-12

我正在与 3d 方库合作,他们返回缺乏类型规范的集合(例如public List getFoo();) ,我正在尝试转换它们的返回类型并返回具有正确类型的列表。

我创建了一个简单的示例来演示该问题。例如

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


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

但如果你从原始类型开始List,然后调用stream()给你一个原始类型的对象Stream反而。

The 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 https://stackoverflow.com/a/37215169/1441122指出,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));
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么这个 java 8 流操作计算结果为 Object 而不是 List 或只是 List? 的相关文章

随机推荐