簡體   English   中英

java streams:直截了當地減少

[英]java streams: straightforward reduce

我有一個MetricGroup流,其中:

public class MetricGroup {

    private int uploadedDocs;
    private long uploadedKbs;

    // getters and setters

}

我需要在一個指標中對所有指標進行sumarize。 我的意思是,我需要將所有metric.uploadedDocs添加到sumMetric.uploadedDocsmetric.uploadedKdssumMetric.uploadedKbs

我發現我需要某種reduce

Stream.of(new MetricGroup(1,100), new MetricGroup(1,200))
    .reduce(????);

有任何想法嗎?

你可以使用reduce這個重載:

T reduce(T identity,
     BinaryOperator<T> accumulator)

像這樣:

.reduce(new MetricGroup(0, 0),
        (x, y) -> new MetricGroup(
                      x.getUploadedDocs() + y.getUploadedDocs()
                      x.getUploadedKbs() + y.getUploadedKbs()
                  )
        )

您還可以使用collect方法:

private static MetricGroup combine(MetricGroup x, MetricGroup y) {
    x.setUploadedDocs(x.getUploadedDocs() + y.getUploadedDocs());
    x.setUploadedKbs(x.getUploadedKbs() + y.getUploadedKbs());
    return x;
}

// ....

.collect(() -> new MetricGroup(0, 0),
    YourClass::combine,
    YourClass::combine
)

為了避免在reduce調用期間創建多個/多個MetricGroup對象,可以分別進行兩次調用以對UploadedDocsUploadedKbs求和,然后構造一個表示結果的新MetricGroup

int uploadedDocsSum = source.stream().mapToInt(MetricGroup::getUploadedDocs).sum();
long uploadedKbsSum = source.stream().mapToLong(MetricGroup::getUploadedKbs).sum();
MetricGroup result = new MetricGroup(uploadedDocsSum, uploadedKbsSum);

可以說更具可讀性......

只需傳入一個lambda(將操縱現有的MetricGroup)

Stream.of(new MetricGroup(1, 100), new MetricGroup(1, 200))
    .reduce((a, b) -> {
      a.setUploadedDocs(a.getUploadedDocs() + b.getUploadedDocs());
      a.setUploadedKbs(a.getUploadedKbs() + b.getUploadedKbs());
      return a;
    });

// Optional[F.MetricGroup(uploadedDocs=2, uploadedKbs=300)]

或者,真正獲得一個新的MetricGroup(不需要操作現有的MetricGroup)

Stream.of(new MetricGroup(1, 100), new MetricGroup(1, 200))
        .reduce((a, b) -> new MetricGroup(a.getUploadedDocs() + b.getUploadedDocs(), a.getUploadedKbs() + b.getUploadedKbs()));

與java流一樣,您實際上不必使用它們。 我建議創建一個簡單的簡化輔助方法:

public static MetricGroup reduce(Iterable<? extends MetricGroup> metrics){
   int uploadedDocs = 0;
   long uploadedKbs = 0L;
   for(MetricGroup metric : metrics){
       uploadedDocs += metric.getUploadedDocs();
       uploadedKbs += metric.getUploadedKbs();
   }
   return new MetricGroup(uploadedDocs, uploadedKbs);
}

如果你不能改變你開始使用流,你仍然可以使用上面的方法,只需傳遞一個對Stream.iterator()方法的引用:

MetricGroup reduced = reduce(stream::iterator);

如果你想使用簡化,我建議將MetricGroup設為值類型,方法是將字段MetricGroup final,添加零,並用組合方法替換setter。

public class MetricGroup {
    private final int uploadedDocs;
    private final long uploadedKbs;

    // obvious constructor
    // getters

    public static final ZERO = new MetricGroup(0, 0);

    public MetricGroup add(MetricGroup a, MetricGroup b) {
        return new MetricGroup(a.uploadedDocs + b.upLoadedDocs,
                               a.uploadedKbs + b.uploadedKbs);
    }

    public MetricGroup uploadOneDoc(long kbs) {
        return new MetricGroup(uploadedDocs + 1, uploadedKbs + kbs);
    }
}

這樣可以很好地執行流操作:

MetricGroup sum = metricGroups.stream()
                              .reduce(MetricGroup.ZERO, MetricGroup::add);

暫無
暫無

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

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