管理具有多个结果的Java 8流的最佳实践是什么

时间:2018-02-24 20:05:22

标签: java collections foreach java-8 java-stream

当我想从迭代中获得多个结果时,如何使用流处理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();
}

3 个答案:

答案 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收集最终将根据元素序列的类型返回一种事物:单一或集合。
例如,我们可以收集FooList FooMap Foo IntegerStream密钥,等等。 ..
List收集不是为了收集不同的自定义内容,例如Foo List + Bar Bar + Foo的数量+ Stream

正如@Eugene强调的那样,Streams还提供了一种获取IntSummaryStatistics的方法,这是一组事物:最小,最大,总和和平均的常见聚合。 但是,我们不应该考虑它最终收集一件事:统计数据吗?

所以你有三种方式:

  • 为您的用例放置for并保留for循环。

  • 使用多个流:您要收集的自定义内容的一个流。

  • 将单个流与自定义收集器一起使用。

在任何情况下我都不会使用第二种方式,因为它会产生一个不太可读且直接的代码,而不是你的实际代码。

关于Federico Peralta Schaffner回答的最后一种方式(自定义收集器)。它更直,它可以从流并行中受益。所以这是一个可以考虑的选择 但它也需要更多的锅炉板代码,并且有更多的读取间接来理解实际的逻辑 所以我认为我只会在两种情况下引入自定义收集器:

  • 收集器被重复使用。
  • 我们希望受益于流并行性我们需要处理非常重要的元素(Federico Peralta Schaffner在其comment中解释得非常好,谢谢)。

在任何其他情况下,我会保留@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());