lambada表达式 -03

Java8函数式编程(三):Collectors.groupingBy

先祭出VO:

@Getter
@Setter
@ToString
class Fruit {
    private String name;
    private Double price;

    public Fruit(String name, Double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Fruit fruit = (Fruit) o;
        return java.util.Objects.equals(name, fruit.name) &&
                java.util.Objects.equals(price, fruit.price);
    }

    @Override
    public int hashCode() {
        return java.util.Objects.hash(name, price);
    }
    // 注意equals和hashCode必须成对出现
}

1)计数

List<Fruit> fruitList = Lists.newArrayList(new Fruit("apple", 6),
        new Fruit("apple", 6),
        new Fruit("banana", 7), new Fruit("banana", 7),
        new Fruit("banana", 7), new Fruit("grape",8));

Map<String, Long> map = fruitList.stream().
   collect(Collectors.groupingBy(Fruit::getName,Collectors.counting()));

输出结果是:{banana=3, apple=2, grape=1}
换一种啰嗦、复杂的写法,但能加深理解。

Map<String, Long> map = fruitList.stream().map(Fruit::getName).
  collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

2)排序
现在要按照水果map中value的数量逆序打印每个entry

map.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed())
         .forEachOrdered(System.out::println);

3)累加求和

Map<String, Integer> sumMap = fruitList.stream().collect.
(Collectors.groupingBy(Fruit::getName, Collectors.summingInt(Fruit::getPrice)));

输出结果是:{banana=21, apple=12, grape=8}
4)分组

Map<String, List<Fruit>> groupMap = 
fruitList.stream().collect(Collectors.groupingBy(Fruit::getName));

上述代码根据name将list分组,如果name是唯一的,那么上述代码就会显得啰嗦。我们需要知道,Guava补JDK之不足,现在改Guava一显身手了。

Map<String, Fruit> map = Maps.uniqueIndex(fruitList, Fruit::getName);

生成的Map是ImmutableMap,不可更改里面的值。比如map.remove(“apple”)会抛出异常:java.lang.UnsupportedOperationException

根据不同的名字分为若干组

// group by price, uses 'mapping' to convert List<Fruit> to List<String>
Map<String, List<Integer>> groupMap = 
fruitList.stream().collect(Collectors.groupingBy(Fruit::getName, 
Collectors.mapping(Fruit::getPrice, Collectors.toList())));

上面一段代码可以用Guava代替

Multimap<String, Integer> multiMap = ArrayListMultimap.create();
fruitList.forEach(fruit -> multiMap.put(fruit.getName(), fruit.getPrice()));


可以看到有三个参数,第一个参数就是key的Function了,第二个参数是一个map工厂,也就是最终结果的容器,一般默认的是采用的HashMap::new,最后一个参数很重要是一个downstream,类型是Collector,也是一个收集器,那就是说,这三个参数其实就是为了解决分组问题的

第一个参数:分组按照什么分类

第二个参数:分组最后用什么容器保存返回

第三个参数:按照第一个参数分类后,对应的分类的结果如何收集

其实一个参数的Collectors.groupingBy方法的 ,第二个参数默认是HashMap::new, 第三个参数收集器其实默认是Collectors.toList

所以HashMap是无序的大家都是知道的,所以原因找到了。

 

Map<LocalDate, List<Model>> modelMap = modelVOList.stream().collect(Collectors.groupingBy(Model::getGroupTime, LinkedHashMap::new, Collectors.toList()))






posted @ 2022-08-10 10:02  Jerry&Ming  阅读(84)  评论(0)    收藏  举报