Java8 Сбор карт - PullRequest
       14

Java8 Сбор карт

2 голосов
/ 12 марта 2019

У меня есть этот объект:

public class MenuPriceByDay implements Serializable {

    private BigDecimal avgPrice;
    private BigDecimal minPrice;
    private BigDecimal maxPrice;
    private Date updateDate;

..
}

и этот другой:

public class Statistics {

     double min;
     double max;
     double average;

     public Statistics() {
        super();
     }



    public Statistics(double min, double max, double average) {
        super();
        this.min = min;
        this.max = max;
        this.average = average;
    }



}

, а также список цен:

List<MenuPriceByDay> prices = new ArrayList<MenuPriceByDay>();

, который я хочу преобразовать в карту:

Map<LocalDate, Statistics> last30DPerDay =  

        prices
            .stream()
            .collect(Collectors.toMap(MenuPriceByDay::getUpdateDate, p -> new Statistics(   p.getAvgPrice().doubleValue(),
                    p.getMaxPrice().doubleValue(),
                    p.getMinPrice().doubleValue())));

но у меня проблема с компиляцией:

Type mismatch: cannot convert from Map<Date,Object> to 
 Map<LocalDate,Statistics>

Ответы [ 2 ]

2 голосов
/ 12 марта 2019

Обратите внимание, что при использовании Collectors.toMap вы можете получить IllegalStateException, если у вас есть дубликаты ключей.

Если сопоставленные ключи содержат дубликаты (согласно Object.equals (Object)), при выполнении операции сбора создается исключение IllegalStateException.

Вы можете использовать toMap(keyMapper, valueMapper, mergeFunction) вместо.Также есть решение с groupingBy, и в этом случае вы должны решить, какую статистику использовать при дублировании ключа:

Map<LocalDate, Optional<Statistics>> map = prices.stream()
            .collect(groupingBy(p -> p.getUpdateDate()
                            .toInstant()
                            .atZone(ZoneId.systemDefault())
                            .toLocalDate(),
                    mapping(p-> new Statistics(
                            p.getMinPrice().doubleValue(),
                            p.getAvgPrice().doubleValue(),
                            p.getMaxPrice().doubleValue()),
                            reducing((s1, s2) -> ???)      // here
2 голосов
/ 12 марта 2019

UpdateDate относится к типу Date, и вы пытаетесь собрать как LocalDate, поэтому вам просто нужно преобразовать Date в LocalDate:

Map<LocalDate, Statistics> collect = prices.stream()
        .collect(Collectors.toMap(m -> m.getUpdateDate()
        .toInstant()
        .atZone(ZoneId.systemDefault())
        .toLocalDate(),
                 p -> new Statistics(p.getAvgPrice().doubleValue(),
                        p.getMaxPrice().doubleValue(),
                        p.getMinPrice().doubleValue())
        ));

Подробнее о Преобразование даты в LocalDate или LocalDateTime и Back

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

public LocalDate convertToLocalDateViaInstant(Date dateToConvert) {
    return dateToConvert.toInstant()
            .atZone(ZoneId.systemDefault())
            .toLocalDate();
}

, и ваш код может быть:

  Map<LocalDate, Statistics> collect = prices.stream()
            .collect(Collectors.toMap(
                    m -> this.convertToLocalDateViaInstant(m.getUpdateDate()),
                    p -> new Statistics(p.getAvgPrice().doubleValue(),
                            p.getMaxPrice().doubleValue(),
                            p.getMinPrice().doubleValue())
            ));

Лучшее решение

лучшее решение - просто изменить updateDate тип на LocalDate:

private LocalDate updateDate;

, и вы можете просто использовать свой код

...