以结构化方式组合多个Java流

时间:2018-04-24 17:42:37

标签: java java-stream collectors

我想使用Java的流API对对象列表进行一些计算:

List<Item>.stream()...

Item类包含许多属性。对于其中一些我需要取集合中所有项目的平均值,对于其他属性我需要做其他形式的计算。我一直在做单独的流/收集器调用来实现这一点,虽然我没有遇到任何性能问题(因为列表大小通常大约为100)我想学习如何更简洁,也就是循环一次。

ItemCalculation itemCalculation = ItemCalculation.builder()
    .amountOfItems(itemList.size())
    .averagePrice(itemList.stream()
            .mapToDouble(item -> item.getPrice())
            .average()
            .getAsDouble())
    .averageInvestmentValue(itemList.stream()
            .mapToDouble(item -> getTotalInvestmentValue(item.getInvestmentValue(), item.getInvestmentValuePackaging()))
            .average()
            .getAsDouble())
    .highestWarrantyLimit(itemList.stream()... etc.

我读到了关于创建自定义收藏家的信息,但是我的计算和#34;似乎有点奇怪。 class只是一行(stream-&gt; customCollector),然后有一个非常臃肿的收集器类来执行实际的逻辑。特别是因为以不同的方式收集不同的属性,我需要许多不同的中间计数和其他变量。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

不幸的是,似乎无法使用流对其进行合理的改进,以使其在单线程模式下表现更好。

您在问题中提供的代码很容易理解,并且对于现在的小规模收集来说性能足够。

如果您想提高解决方案的性能,则可以以迭代方式对集合进行一次迭代,一次运行即可计算所需的每个输出:

    long amountOfItems = 0;
    double priseSum = 0;
    double highestWarrantyLimit = Double.MIN_VALUE;
    for (Item item : itemList) {
        amountOfItems++;
        priseSum += item.getPrice();
        double investmentValue = getTotalInvestmentValue(item.getInvestmentValue(), item.getInvestmentValuePackaging());
        if (highestWarrantyLimit < investmentValue) {
            highestWarrantyLimit = investmentValue;
        }
    }
    ItemCalculation itemCalculation = ItemCalculation.builder()
            .amountOfItems(amountOfItems)
            .averagePrice(priseSum / amountOfItems)
            .averageInvestmentValue(investmentValueSum / amountOfItems)
            .highestWarrantyLimit(highestWarrantyLimit)
            // ...
            .build(); 

添加了Streams API,以为处理数据元素序列提供库支持,这对于您的情况是非常正确的。但是,流为数据元素强加了一个通用管道,这种情况在您的情况下是不正确的,并使管道看起来像这样:

itemList.stream()
    .collect(toItemCalculation());

这不是很合理,除非您要在多线程模式下使用它。在这种情况下,使用自定义收集器的解决方案将是更可取的,因为用于组合逻辑的脚手架代码已经内置。