当前位置: 首页 > 知识库问答 >
问题:

为什么这个Java8流操作的计算对象不是List或List?

强金鑫
2023-03-14

我正在使用一个3d party库,它们返回缺少类型规范的集合(例如,public List getFoo() ),我试图转换它们的返回类型,并返回一个具有正确类型的列表。

我创建了一个简单的例子来说明这个问题。例如

编辑将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

如果我稍微修改程序,这样它就可以编译,我可以检查流/收集操作的返回类型。它“工作”,尽管我必须转换结果。

例如

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

正如所料。

那么,收藏家们。listCollector()在运行时做的事情是正确的,但是这种编译时行为是预期的吗?如果是这样的话,有没有“适当”的解决方法?


共有2个答案

华衡
2023-03-14

收藏家。toList()返回一个列表,而不是ArrayList。这将汇编:

public static void main(String[] args) {
    ArrayList<?> l = getRawArrayList();
    List<String> l2 = l.stream().map(Object::toString).collect(Collectors.toList());

}
丁承德
2023-03-14

stream()map()collect(),以及所有其他流方法都依赖于泛型类型才能正常工作。如果使用原始类型作为输入,那么所有泛型都会被删除,所有内容都会变成原始类型。例如,如果你有一个列表

但是,如果你从一个原始类型列表开始,那么调用流()会给你一个原始类型流的对象。

map()方法有以下声明:

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

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

    Stream map(Function mapper)

所以调用map()的结果就是一个简单的StreamCollection()的签名用泛型填充:

    <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不兼容

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

此外,正如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:(编译时出错:https : //gyazo.com/cd3c21a8562589451814903febaf89fe) 源代码2 :(编译好的代码) 问题答案: 因为在第一个示例中您输入错误: 应该是

  • 本文向大家介绍JAVA8 List > list中再装一个list转成一个list操作,包括了JAVA8 List > list中再装一个list转成一个list操作的使用技巧和注意事项,需要的朋友参考一下 我就废话不多说了,大家还是直接看代码吧~ 补充知识:java 8 转复杂的list对象转为单一的list 我就废话不多说了,大家还是直接看代码吧~ journal.snList= Arrays

  • 我得到两个错误: Java:不兼容类型:无法推断类型变量R(参数不匹配;方法引用无效) 对toString的引用是不明确的,java.lang.Integer中的方法toString(int)和java.lang.Integer中的方法toString()都是不明确的 并且编译器无法推断所需的方法引用。 但是关于第二个,编译器引用的静态上下文在哪里? 这个错误与Integer类的方法toStrin

  • 公共静态无效字(字符串文本){int numWords=1; 字符串“是this_one_long_word还是几个???你觉得怎么样??太多“应该打印10个字和”!这使用periods.as.word.delimiters,可能很棘手。“应该打印10个单词。 描述如下:一个单词是由一个或多个字符组成的序列,由空格或句子终止符(句号、冒号、分号、问号、感叹号)分隔,无论它是否为实际的英语单词。空白

  • 对于特定的任务,我需要在可变数组中进行大量快速、单独的写操作。为了检查性能,我使用了以下测试: