我有一个自定义对象项,其中有两个字段数量和税额。我有一个Itemized对象的数组,我想对同一流中的两个字段求和。下面是我如何计算两个字段的总和。
double totalAmount = Arrays.stream(getCharges()).map(Itemized::getAmount).reduce(0.0, Double::sum));
double totalTax = Arrays.stream(getCharges()).map(Itemized::getTax).reduce(0.0, Double::sum));
有什么方法我不必两次解析流,并且可以一次性汇总两个字段?我不希望对totalTax和totalAmount求和,但要分别求和。我当时在看收集器,但找不到任何可以一口气汇总多个字段的示例。
使用for循环?
double taxSum = 0;
double amountSum = 0;
for (Itemized itemized : getCharges()) {
taxSum += itemized.getTax();
amountSum += itemized.getAmount();
}
您可以尝试使用T型收集器,就像这样:
Arrays.stream(getCharges()) // Get the charges as a stream
.collect(Collectors // collect
.teeing( // both of the following:
Collectors.summingDouble(Itemized::getAmount), // first, the amounts
Collectors.summingDouble(Itemized::getTax), // second, the sums
Map::entry // and combine them as an Entry
)
);
这应该为您提供一个Map.Entry<Double, Double>
,以金额总和作为键,并以税收总和作为值,您可以提取。
编辑:测试并编译它-它可以工作。我们开始:
ItemizedTest.java
public class ItemizedTest
{
static Itemized[] getCharges()
{
// sums should be first param = 30.6, second param = 75
return new Itemized[] { new Itemized(10, 20), new Itemized(10.4,22), new Itemized(10.2, 33) };
}
public static void main(String[] args)
{
Map.Entry<Double, Double> sums = Arrays.stream(getCharges())
.collect(Collectors
.teeing(
Collectors.summingDouble(Itemized::getAmount),
Collectors.summingDouble(Itemized::getTax),
Map::entry
)
);
System.out.println("sum of amounts: "+sums.getKey());
System.out.println("sum of tax: "+sums.getValue());
}
}
Itemized.java
public final class Itemized
{
final double amount;
final double tax;
public double getAmount()
{
return amount;
}
public double getTax()
{
return tax;
}
public Itemized(double amount, double tax)
{
super();
this.amount = amount;
this.tax = tax;
}
}
输出:
金额总和:30.6税项总和:75.0
P.S。:teeing
收集器仅在Java 12+中可用。
而不是按字段求和,而是定义一个自定义对象来保存两个字段的和值:
ItemizedValues {
private double amount;
private double tax;
public static final ItemizedValues EMPTY = new ItemizedValues(0, 0);
// Constructor - getter - setter
public static ItemizedValues of(Itemized item) {
return new ItemizedValues(amount, tax);
}
public static ItemizedValues sum(ItemizedValues a, ItemizedValues b) {
// Sum the fields respectively
// It's your choice to reuse the existing instances, modify the values or create a brand new one
}
}
Arrays.stream(getCharges())
.map(ItemizedValues::of)
.reduce(ItemizedValues.EMPTY, ItemizedValues::sum);
通过一种数据结构,可以使两个累加起来,您可以将流简化为单个对象。
[这是使用double[]
将totalAmount
保留在索引0,将totalTax
保留在索引1(其他选项包括SimpleEntry
,Pair
):
double[] res = Arrays.stream(getCharges())
.map(ch -> new double[] { ch.getAmount(), ch.getTax() })
.reduce(new double[] { 0, 0 },
(a1, a2) -> new double[] { a1[0] + a2[0], a1[1] + a2[1] });
double totalAmount = res[0],
totalTax = res[1];
您可以使用Entry
来做到这一点,但仍然会创建很多对象,我建议的最佳解决方案是for loop
并由NimChimpsky回答
Entry<Double, Double> entry = Arrays.stream(new Itemized[] {i1,i2})
.map(it->new AbstractMap.SimpleEntry<>(it.getAmount(), it.getTax()))
.reduce(new AbstractMap.SimpleEntry<>(0.0,0.0),
(a,b)->new AbstractMap.SimpleEntry<>(a.getKey()+b.getKey(),a.getValue()+b.getValue()));
System.out.println("Amount : "+entry.getKey());
System.out.println("Tax : "+entry.getValue());
在您的特定情况下,可以通过使用Itemized类作为值持有者来完成。
Itemized result = Arrays.stream(getCharges())
.reduce(new Itemized(), (acc, item) -> {
acc.setAmount(acc.getAmount() + item.getAmount());
acc.setTax(acc.getTax() + item.getTax());
return acc;
});
double totalAmount = result.getAmount();
double totalTax = result.getTax();