让我们说我们必须使用这段无聊的代码:
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;)
我尝试了这个参数,但它给了我未定义的A
和R
,而且IDE还没有给出更多的建议。
我很好奇,你如何在这种情况下使用collect call
,我找不到任何可以指导我的信息。任何人都可以发光吗?
答案 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