2016-04-07 12 views
4
のJavaストリーム(と条件付きストリーム操作)で複数のフィールドを

追加します反復が行われたときに戻ります。だが、私はこのクラスを持っているとしましょう

しかし、私が望むのは、Javaストリームでこれを達成することです。以下は、私が持っているものである - それは動作しますが、私は1つのストリームにそれを凝縮させる方法がなければならないように感じる:

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); 
} 

私は疑う答えは3つの引数を取りreduce()方法は、1ですそのうちの1つは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()ものを成功させようとしていました。

答えて

3

、あなたは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); 
} 
1

最初の方法では、すべてfield1field2を合計し、nullを無視します。あなたは、あなたが暗示したように、3つの引数reduceメソッドによって、単一のストリームパイプラインでこれを行うことができます。

この場合、IDはまだBigDecimal.ZEROです。アキュムレータ関数は、ヌルでない場合、現在の累積結果に各フィールドを加算します。最後に、並列処理にのみ使用されるコンバイナには、2つの値が追加されます(BigDecimal)。

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); 
} 

別の同等:

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); 
} 

同じことが、この場合には、あなたは彼らがnullているかどうかに応じて、otherField1otherField2またはotherField3間の差異を合計したい、あなたの第二の例のために行きますこのタスクを解決する方法は、map()を使用することです:その場合は、各要素を合計したい値にマップし、すべてBigIntegerを合計することによってストリームを減らします。たとえば、最初の例では、nullの可能性を考慮して、Thingfield1field2の合計にマップします。

あなたが均一にフィールドを治療しようとしているので
5

使うcollect()、カスタムコレクタヘルパーではなく、IntSummaryStatisticsとは異なり。

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); 
    } 

}

:あなたのヘルパークラスのようなものになります

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

関連する問題