当我想从迭代中获得多个结果时,如何使用流处理Java 8中的forEach。当然在stream forEach操作中调用List.add方法不是一个选项......你将如何使用Java 8流重写这段代码?
additionalWebsitesList = Lists.newArrayList();
String additionalWebistesCsv = "";
for (String website : additionalWebsites) {
WebsiteModel websiteModel = getWebsiteModel(website);
//How this can be processed via Stream???
additionalWebsitesList.add(websiteModel);
areaModels.addAll(websiteModel.getAreas());
additionalWebistesCsv += websiteModel.getId();
}
答案 0 :(得分:4)
使用流做这样的事情的方法是使用自定义收集器。假设我们定义了以下类:
public class Results {
private final List<WebsiteModel> additionalWebsitesList = new ArrayList<>();
private final List<AreaModel> areaModels = new ArrayList<>();
private final StringBuilder additionalWebsitesCsv = new StringBuilder();
public void accumulate(WebsiteModel websiteModel) {
additionalWebsitesList.add(websiteModel);
areaModels.addAll(websiteModel.getAreas());
additionalWebsitesCsv.append(websiteModel.getId());
}
public void combine(Results another) {
additionalWebsitesList.addAll(another.additionalWebsitesList);
areaModels.addAll(another.areaModels);
additionalWebsitesCsv.append(another.additionalWebsitesCsv);
}
public List<WebsiteModel> getAdditionalWebsitesList() {
return additionalWebsitesList;
}
public List<AreaModel> getAreaModels() {
return areaModels;
}
public String getAdditionalWebsitesCsv() {
return additionalWebsitesCsv.toString();
}
}
有了这个Results
课程,您就可以收集结果了:
Results results = additionalWebsites.stream()
.map(this::getWebsiteModel)
.collect(Results::new, Results::accumulate, Results::combine);
这使用Stream.collect
方法。第一个参数是Supplier
,它创建了可变对象,通过第二个参数中提供的累加器将流的元素累积到该对象中。第三个参数是合并,如果流是并行的,它将仅用于组合部分结果。
答案 1 :(得分:3)
使用多个管理Java 8流的最佳实践是什么? 结果
当然在stream forEach操作中调用List.add方法不是 一个选项。
最佳做法是不强制您使用流,因为用例不合适
Stream
接口javadoc将自身描述为:
支持顺序和并行聚合的一系列元素 操作。
Stream
操作返回一系列类型元素
所以Stream
收集最终将根据元素序列的类型返回一种事物:单一或集合。
例如,我们可以收集Foo
,List
Foo
,Map
Foo
Integer
个Stream
密钥,等等。 ..
List
收集不是为了收集不同的自定义内容,例如Foo
List
+ Bar
Bar
+ Foo
的数量+ Stream
。
正如@Eugene强调的那样,Streams还提供了一种获取IntSummaryStatistics
的方法,这是一组事物:最小,最大,总和和平均的常见聚合。
但是,我们不应该考虑它最终收集一件事:统计数据吗?
所以你有三种方式:
为您的用例放置for
并保留for
循环。
使用多个流:您要收集的自定义内容的一个流。
将单个流与自定义收集器一起使用。
在任何情况下我都不会使用第二种方式,因为它会产生一个不太可读且直接的代码,而不是你的实际代码。
关于Federico Peralta Schaffner回答的最后一种方式(自定义收集器)。它更直,它可以从流并行中受益。所以这是一个可以考虑的选择 但它也需要更多的锅炉板代码,并且有更多的读取间接来理解实际的逻辑 所以我认为我只会在两种情况下引入自定义收集器:
在任何其他情况下,我会保留@NgModule({
imports: [BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes)],
declarations: [IndexComponent],
exports: [IndexComponent]
})
循环。
答案 2 :(得分:1)
该代码为Java 8流:
additionalWebsitesList = additionalWebsites.stream()
.map(this::getWebsiteModel)
.collect(Collectors.toList());
areaModels = additionalWebsites.stream()
.flatMap(w -> getWebsiteModel(w).getAreas().stream())
.collect(Collectors.toList());
String additionalWebistesCsv = additionalWebsites.stream()
.map(this::getWebsiteModel)
.map(WebsiteModel::getId)
.collect(Collectors.joining());