потоки Java: прямое сокращение - PullRequest
0 голосов
/ 08 января 2019

У меня есть поток MetricGroup, где:

public class MetricGroup {

    private int uploadedDocs;
    private long uploadedKbs;

    // getters and setters

}

Мне нужно объединить все метрики в одну метрику. Я имею в виду, мне нужно добавить все metric.uploadedDocs в sumMetric.uploadedDocs и metric.uploadedKds в sumMetric.uploadedKbs.

Я понял, мне нужен какой-то reduce

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

Есть идеи?

Ответы [ 5 ]

0 голосов
/ 08 января 2019

Если вы хотите использовать сокращение, я бы рекомендовал сделать MetricGroup типом значения, сделав поля окончательными, добавив ноль и заменив сеттеры методами объединения.

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);
0 голосов
/ 08 января 2019

Как всегда с потоками 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);
0 голосов
/ 08 января 2019

Просто передать в одну лямбду (будет манипулировать существующей 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 (не манипулируя существующей)

Stream.of(new MetricGroup(1, 100), new MetricGroup(1, 200))
        .reduce((a, b) -> new MetricGroup(a.getUploadedDocs() + b.getUploadedDocs(), a.getUploadedKbs() + b.getUploadedKbs()));
0 голосов
/ 08 января 2019

Чтобы избежать создания нескольких / многих MetricGroup объектов во время вызова reduce, вы можете сделать два отдельных вызова для суммирования UploadedDocs и UploadedKbs соответственно, а затем создать новый MetricGroup, представляющий результат .

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

Возможно, более читабельно ...

0 голосов
/ 08 января 2019

Вы можете использовать эту перегрузку 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
)
...