如何在Java 8中使用collect调用?

时间:2014-11-13 09:25:09

标签: java java-8 java-stream collect

让我们说我们必须使用这段无聊的代码:

ArrayList<Long> ids = new ArrayList<Long>();
for (MyObj obj : myList){
    ids.add(obj.getId());
}

切换到Java 8后,我的IDE告诉我可以用collect call替换此代码,并自动生成:

ArrayList<Long> ids = myList.stream().map(MyObj::getId).collect(Collectors.toList());

然而它给了我这个错误:

  Steam中的

collect(java.util.stream.Collector)无法应用于:(java.util.stream.Collector,capture,java.util.List&gt;)

我尝试了这个参数,但它给了我未定义的AR,而且IDE还没有给出更多的建议。

我很好奇,你如何在这种情况下使用collect call,我找不到任何可以指导我的信息。任何人都可以发光吗?

2 个答案:

答案 0 :(得分:47)

问题是,Collectors.toList毫不奇怪地返回List<T>。不是ArrayList

List<Long> ids = remove.stream()
        .map(MyObj::getId)
        .collect(Collectors.toList());

编入interface

来自文档:

  

返回一个Collector,它将输入元素累积为一个新元素   List没有类型保证,可变性,   List返回的可序列化或线程安全性;如果更多   需要控制返回的List,使用   toCollection(Supplier)

强调我的 - 你甚至不能假设返回的List是可变的,更不用说它是一个特定的类。如果您想要ArrayList

ArrayList<Long> ids = remove.stream()
        .map(MyObj::getId)
        .collect(Collectors.toCollection(ArrayList::new));

另请注意,习惯使用import static和Java 8 Stream API,因此添加:

import static java.util.stream.Collectors.toCollection;

(我讨厌已加星标import static,除了污染命名空间并添加混淆之外什么也没做。但是选择性import static,尤其是Java 8实用程序类,可以大大减少冗余代码)

会导致:

ArrayList<Long> ids = remove.stream()
        .map(MyObj::getId)
        .collect(toCollection(ArrayList::new));

答案 1 :(得分:2)

我使用了很多收集器块,我在其中创建一个空数组并使用循环填充它,所以我决定我需要一个自己的实用程序类,不要再次再次编写相同的行,这里是:

public class Collections {

    public static <T, O> List<T> collect(Set<O> items, Function<? super O, ? extends T> mapper) {

    return items.stream().map(mapper).collect(Collectors.toCollection(ArrayList::new));
}

}

并像这样使用

List<Product> prods = Collections.collect(basket.getOrderItems(), OrderItem::getProduct);

或者像这样

List<Long> prods = Collections.collect(basket.getOrderItems(), (item)->item.getProduct().getId());

虽然它可能看起来更容易阅读,但在这种情况下,流似乎有点慢,look here