Группировка значений в Ha sh Карта в Java Поток с использованием пользовательского объекта Collector? - PullRequest
2 голосов
/ 13 января 2020

Java Stream newb ie здесь. В данный момент я заканчиваю главу 6 ( Сбор данных с потоками ) о коллекторах из этой книги .

Мой объект выглядит следующим образом.

    public class Report {

    private String movie;
    private int movieId;
    private int projections;
    private int tickets;
    private double income;
}

Идея в том, чтобы получить какой-то общий сводный отчет. В основном, HashMap<String, Double>, который будет иметь три пары ключ-значение.

Ключ 1:

projections - который будет представлять сумму всех прогнозов из каждого Отчета.

Ключ 2:

tickets - который будет представлять сумму всех билетов из каждого отчета.

Ключ 3:

income - который будет представлять сумму всех доходов от каждого отчета.

Теперь я на самом деле выполнил задание, создав собственный коллектор под названием MapCollector.

    public class MapCollector implements Collector<Report, Map<String, Double>, Map<String, Double>>{

    @SuppressWarnings("serial")
    @Override
    public Supplier<Map<String, Double>> supplier() {

        return () ->  new HashMap<String, Double>() {{
            put("projections", 0.0);
            put("tickets", 0.0);
            put("income", 0.0);
        }};
    }

    @Override
    public BiConsumer<Map<String, Double>, Report> accumulator() {

        return (map, report) -> 
        {
            map.put("projections", map.get("projections") + report.getProjections());
            map.put("tickets", map.get("tickets") + report.getTickets());
            map.put("income", map.get("income") + report.getIncome());          
        };
    }

    @Override
    public BinaryOperator<Map<String, Double>> combiner() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Function<Map<String, Double>, Map<String, Double>> finisher() {
        // TODO Auto-generated method stub
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        // TODO Auto-generated method stub
        return Collections.unmodifiableSet(EnumSet.of(
                IDENTITY_FINISH, CONCURRENT));
    }
}

Итак, полученный мной результат, который работает, выглядит следующим образом:

HashMap<String, Double> result = (HashMap<String, Double>) reports.stream().collect(new MapCollector());

Так что мой вопрос есть, почему сделать это по-другому, не создавая новый объект Collector? Может быть, как-то это сделать с groupingBy, или с reduce? Или любым другим (лучше) более читабельным способом?

1 Ответ

0 голосов
/ 13 января 2020

Для этого вам не нужен пользовательский коллектор. Все, что вам нужно, это supplier, accumulator и combiner.

. Вы можете поместить их в тот же класс, что и поток, и вызвать его следующим образом:

HashMap<String, Double> result = (HashMap<String, Double>) 
                                 reports.stream()
                                        .collect(
                                          this::supplier,
                                          this::acumulator,
                                          this::combiner);

Где методы будут выглядеть следующим образом:

private Map<String, Double> supplier() {
    return new HashMap<String, Double>() {{
        put("projections", 0.0);
        put("tickets", 0.0);
        put("income", 0.0);
    }};
}

private void accumulator(Map<String, Double> map, Report report) {
    map.merge("projections", report.getProjections(), Double::sum);
    map.merge("tickets", report.getTickets(), Double::sum);
    map.merge("income", report.getIncome(), Double::sum);
}

private void combiner(Map<String, Double> firstMap, Map<String, Double> secondMap) {
    secondMap.forEach((k, v) -> firstMap.merge(k, v, Double::sum));
}
...