23

假设我们有这段无聊的代码,我们都必须使用:

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

我尝试转换参数,但它给了我 undefined Aand R,并且 IDE 没有提供更多建议。

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

4

2 回答 2

47

问题在于Collectors.toList,毫不奇怪,它返回一个List<T>. 不是一个ArrayList

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

程序到interface.

从文档中:

返回 a Collector,将输入元素累积到一个新的 List中。不保证返回的类型、可变性、可序列化性或线程安全性List;如果需要对返回的列表进行更多控制,请使用 toCollection(Supplier).

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

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

另请注意,通常import static与 Java 8 StreamAPI 一起使用,因此添加:

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

(我讨厌starred import static,它只会污染命名空间并增加混乱。但是选择性import static,尤其是Java 8实用程序类,可以大大减少冗余代码)

会导致:

ArrayList<Long> ids = remove.stream()
        .map(MyObj::getId)
        .collect(toCollection(ArrayList::new));
于 2014-11-13T09:29:32.923 回答
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());

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

于 2015-04-25T04:01:24.587 回答