簡體   English   中英

在Java流中添加多個字段(以及條件流操作)

[英]Adding multiple fields in Java streams (and conditional stream operations)

假設我有這個課程:

public class Thing {
    private BigDecimal field1;
    private BigDecimal field2;

    private BigDecimal otherField1;
    private BigDecimal otherField2;
    private BigDecimal otherField3;
}

並且在另一個類中,我在每個List<Thing> things ,將field1和field2添加到迭代完成時返回的總和。

但我想要的是用Java流來實現這一目標。 以下是我所擁有的 - 它的工作原理,但我覺得必須有一種方法可以將其濃縮為一個流:

public BigDecimal addFields(List<Thing> things) {
    BigDecimal field1sum = things.parallelStream()
                                     .filter(thing -> thing.getField1() != null)
                                     .map(Thing::getField1)
                                     .reduce(BigDecimal.ZERO, BigDecimal::add);

     BigDecimal field2sum = things.parallelStream()
                                     .filter(thing -> thing.getField2() != null)
                                     .map(Thing::getField2)
                                     .reduce(BigDecimal.ZERO, BigDecimal::add);
     return field1sum.add(field2sum);
}

我懷疑答案是reduce()方法,它接受三個參數,其中一個是BiFunction,但我無法弄清楚如何使其工作。 編輯:我想我可以傳入(x,y) -> x.add(y)reduce() ,但問題是如何map()這兩個字段?

另外,是否有可能/如何將此命令式代碼轉換為功能流?

public BigDecimal addOtherFields(List<Thing> things) {
    BigDecimal result = BigDecimal.ZERO;
    for (Thing thing : things) {
        if (thing.getOtherField2() != null) {
            BigDecimal otherField2 = thing.getOtherField2();
            otherField2 = thing.getOtherField1().subtract(otherField2);
            result = result.add(otherField2);
         } else if (thing.getOtherField3() != null) {
            BigDecimal otherField3 = thing.getOtherField3();
            otherField3 = thing.getOtherField1.subtract(otherField3);
            result = result.add(otherField3);
         }
     }
     return result;
 }

或者,為了更精確一點,我將如何處理基於流的方法中的條件檢查? 我試圖filter()事情沒有成功。

使用帶有自定義收集器幫助程序的collect() ,與IntSummaryStatistics不同。

things.stream()
      .collect(ThingCollectorHelper::new, 
               ThingCollectorHelper::accept,
               ThingCollectorHelper::combine);

你的助手類將是這樣的:

class ThingCollectorHelper {
    BigDecimal sum1 = BigDecimal.ZERO;
    BigDecimal sum2 = BigDecimal.ZERO;

    void accept(Thing t) {
        if (t.field1 != null)
            sum1 = sum1.plus(t.field1);
        if (t.field2 != null)
            sum2 = sum2.plus(t.field2);
    }

    void combine(ThingCollectorHelper other) {
        sum1 = sum1.plus(other.sum1);
        sum2 = sum2.plus(other.sum2);
    }

}

由於您要統一處理字段,您可以考慮使用flatMap

public BigDecimal addFields(List<Thing> things) {
    return things.parallelStream()
        .flatMap(thing -> Stream.of(thing.getField1(), thing.getField2()))
        .filter(Objects::nonNull)
        .reduce(BigDecimal.ZERO, BigDecimal::add);
}
public BigDecimal addOtherFields(List<Thing> things) {
    return things.parallelStream()
        .flatMap(thing ->
            Stream.of(thing.getOtherField2(), thing.getOtherField3())
                .filter(Objects::nonNull)
                .map(thing.getOtherField1()::subtract)
        ).reduce(BigDecimal.ZERO, BigDecimal::add);
}

在第一種方法中,您希望將所有field1field2在一起,忽略null 您可以使用單個Stream管道執行此操作,如您所暗示的那樣,使用3參數reduce方法。

在這種情況下,標識仍然是BigDecimal.ZERO 如果每個字段不為空,則累加器函數會將當前累加的結果添加到每個字段。 最后,僅用於並行處理的組合器添加了兩個BigDecimal值。

public BigDecimal addFields(List<Thing> things) {
    return things.parallelStream().reduce(BigDecimal.ZERO, (a, t) -> {
         if (t.getField1() != null) a = a.add(t.getField1());
         if (t.getField2() != null) a = a.add(t.getField2());
         return a;
     }, BigDecimal::add);
}

第二個示例也是如此,在這種情況下,您希望將otherField1otherField2otherField3之間的差異otherField1 ,具體取決於它們是否為null

public BigDecimal addOtherFields(List<Thing> things) {
    return things.stream().reduce(BigDecimal.ZERO, (a, t) -> {
        if (t.getOtherField2() != null) {
            return a.add(t.getOtherField1().subtract(t.getOtherField2()));
        } else if (t.getOtherField3() != null) {
            return a.add(t.getOtherField1().subtract(t.getOtherField3()));
        }
        return a;
    }, BigDecimal::add);
 }

解決此任務的另一種等效方法是使用map() :在這種情況下,您可以將每個元素映射到您想要求和的值,並通過對所有BigInteger求和來減少Stream。 例如,在第一個例子中,你將每個地圖Thing進入的總和field1field2 ,考慮到其潛在的null -ness。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM