以结构化方式组合多个 java 流
Combining multiple java streams in a structured way
我想使用 Java 的流 API 对对象列表进行一些计算:
List<Item>.stream()...
Item
class 包含许多属性。对于其中一些,我需要取集合中所有项目的平均值,对于其他属性,我需要进行其他形式的计算。我一直在进行单独的 stream/collector 调用来实现这一点,尽管我没有 运行 遇到任何性能问题(因为列表大小通常约为 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.
我阅读了有关创建自定义收集器的内容,但让我的 "calculation" class 只是一行 (stream->customCollector) 然后有一个非常臃肿的收集器似乎有点奇怪 class 执行实际逻辑。特别是因为不同的属性是以不同的方式收集的,所以我需要许多不同的中间计数和其他变量。有什么想法吗?
不幸的是,似乎无法使用流对其进行合理改进,使其在单线程模式下表现更好。
您在问题中提供的代码清晰易懂,并且对于现在的小型集合而言性能足够。
如果您想提高解决方案的性能,您可以以迭代的方式对您的集合进行一次迭代,在单个 运行:
中计算您需要的每个输出
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();
添加了流 API 来为处理数据元素序列提供库支持,这对您的情况来说非常正确。但是,流为数据元素强加了一个通用管道,这对您的情况来说是不正确的,并且使管道看起来像:
itemList.stream()
.collect(toItemCalculation());
这不是很合理,除非你要在多线程模式下使用它。在这种情况下,使用自定义收集器的解决方案会更好,因为用于组合逻辑的脚手架代码已经内置。
我想使用 Java 的流 API 对对象列表进行一些计算:
List<Item>.stream()...
Item
class 包含许多属性。对于其中一些,我需要取集合中所有项目的平均值,对于其他属性,我需要进行其他形式的计算。我一直在进行单独的 stream/collector 调用来实现这一点,尽管我没有 运行 遇到任何性能问题(因为列表大小通常约为 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.
我阅读了有关创建自定义收集器的内容,但让我的 "calculation" class 只是一行 (stream->customCollector) 然后有一个非常臃肿的收集器似乎有点奇怪 class 执行实际逻辑。特别是因为不同的属性是以不同的方式收集的,所以我需要许多不同的中间计数和其他变量。有什么想法吗?
不幸的是,似乎无法使用流对其进行合理改进,使其在单线程模式下表现更好。
您在问题中提供的代码清晰易懂,并且对于现在的小型集合而言性能足够。
如果您想提高解决方案的性能,您可以以迭代的方式对您的集合进行一次迭代,在单个 运行:
中计算您需要的每个输出 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();
添加了流 API 来为处理数据元素序列提供库支持,这对您的情况来说非常正确。但是,流为数据元素强加了一个通用管道,这对您的情况来说是不正确的,并且使管道看起来像:
itemList.stream()
.collect(toItemCalculation());
这不是很合理,除非你要在多线程模式下使用它。在这种情况下,使用自定义收集器的解决方案会更好,因为用于组合逻辑的脚手架代码已经内置。