java Collectors之 groupingBy,toMap

1,groupingBy

是Java8收集器中的一种,与SQL的GROUP BY子句类似的功能。

1.1,分组

// 根据unitcode进行分组,将unitcode相同的CbhsHsunitInfEntity实体放入list中,
// 此时key是unitcode,value是list
Map<String, List<CbhsHsunitInfEntity>> unitMap = commonApiDao.getScrollData(CbhsHsunitInfEntity.class).getResultlist().stream().collect(Collectors.groupingBy(CbhsHsunitInfEntity::getUnitcode));
}));

1.2,计数

// 根据unitcode进行分组,将unitcode相同的CbhsHsunitInfEntity实体放入list中,
// 此时key是unitcode,value是list.size()
Map<String, List<CbhsHsunitInfEntity>> unitMap = commonApiDao.getScrollData(CbhsHsunitInfEntity.class).getResultlist().stream().collect(Collectors.groupingBy(CbhsHsunitInfEntity::getUnitcode,Collectors.counting()));

参考链接:java8 特性 - groupingBy

1.3,累和

// 根据unitcode进行分组,将unitcode相同的CbhsHsunitInfEntity实体放入list中,
// 此时key是unitcode,value是list中每个price的累和
Map<String, List<CbhsHsunitInfEntity>> unitMap = commonApiDao.getScrollData(CbhsHsunitInfEntity.class).getResultlist().stream().collect(Collectors.groupingBy(CbhsHsunitInfEntity::getUnitcode,Collectors.summingInt(CbhsHsunitInfEntity::getPrice)));

1.4,排序并打印数据

// 现在要按照map中value的数量逆序打印每个entry
Map<String, Long> map = fruitList.stream().map(Fruit::getName).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
map.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed())
         .forEachOrdered(System.out::println);

参考链接:Java8函数式编程(三):Collectors.groupingBy

2,toMap

2.1 将list转换为map,并设置key,value

部分源码:

public static <T, K, U> Collector<T, ?, Map<K,U>> 
		toMap(Function<? super T, ? extends K> keyMapper,
             Function<? super T, ? extends U> valueMapper) {
        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
    }

public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> 
		toMap(Function<? super T, ? extends K> keyMapper,
              Function<? super T, ? extends U> valueMapper,
              BinaryOperator<U> mergeFunction,
              Supplier<M> mapSupplier) {
        BiConsumer<M, T> accumulator
                = (map, element) -> map.merge(keyMapper.apply(element),
                                              valueMapper.apply(element), mergeFunction);
        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
    }

这是一个将List>类型转换为map类型

// 输出一个map类型的数据,其中,unitcode为key值,levelcode2为value值
String sqlks1 = "select distinct levelcode2,b.unitcode from sys_info a,sys_info_unitmap b where a.code=b.kscode ";
Map<String, String> unitKsMap = jdbcTemplate.queryForList(sqlks1).stream().collect(Collectors.toMap(new Function<Map<String, Object>, String>() 
	{
         @Override
         public String apply(Map<String, Object> stringObjectMap) {
             return stringObjectMap.get("unitcode").toString();
         }
     }, new Function<Map<String, Object>, String>() {
         @Override
         public String apply(Map<String, Object> stringObjectMap) {
             return stringObjectMap.get("levelcode2").toString();
         }
     }));

这是一个将List<实体类>类型转换为map类型

class Book {
    private String name;
    private int releaseYear;
    private String isbn;
}
public Map<String, String> listToMap(List<Book> books) {
    return books.stream().collect(Collectors.toMap(Book::getIsbn, Book::getName));
}

或者key值和value值都可以进行拼接

Map<String, BigDecimal> ksLabCostMap = cbhsXmftKsempcostEntityList.stream().collect(
    Collectors.toMap(k -> k.getKscode()+"#"+k.getEmptitlecode(),part -> part.getUnittimecost())
);

2.2 冲突key处理

注意:当key值不唯一的时候,则需要引入一个合并函数,而这个合并函数使得保留了第一个key,后面如果有重复性的key值则不会被采纳

public Map<Integer, Book> listToMapWithDupKey(List<Book> books) {
    return books.stream().collect(Collectors.toMap(Book::getReleaseYear, Function.identity(),
      (existing, replacement) -> existing));
}

2.3 List 转 ConcurrentMap

1,什么是ConcurrentMap?

ConcurrentHashMap是一个线程安全,并且是一个高效的HashMap。
与HashMap不同的是,ConcurrentHashMap中多了一层数组结构,由Segment和HashEntry两个数组组成。其中Segment起到了加锁同步的作用,而HashEntry则起到了存储K.V键值对的作用。

java Collectors之 groupingBy,toMap_第1张图片

在多线程中,每一个Segment对象守护了一个HashEntry数组,当对ConcurrentHashMap中的元素修改时,在获取到对应的Segment数组角标后,都会对此Segment对象加锁,之后再去操作后面的HashEntry元素,这样每一个Segment对象下,都形成了一个小小的HashMap,在保证数据安全性的同时,又提高了同步的效率。只要不是操作同一个Segment对象的话,就不会出现线程等待的问题!

相关链接:
Java集合–ConcurrentMap
ConcurrentHashMap 原理解析(JDK1.8

public Map<Integer, Book> listToConcurrentMap(List<Book> books) {
    return books.stream().collect(Collectors.toMap(Book::getReleaseYear, Function.identity(),
      (o1, o2) -> o1, ConcurrentHashMap::new));
}

2.4 Sorted Map

public TreeMap<String, Book> listToSortedMap(List<Book> books) {
    return books.stream() 
      .sorted(Comparator.comparing(Book::getName))
      .collect(Collectors.toMap(Book::getName, Function.identity(), (o1, o2) -> o1, TreeMap::new));
}

参考链接:Java 8特性 - Collectors toMap

遇到到,补充一点(后面有空再补充):
根据实体类CbhsXmftUnitmapEntity中的ItemCode,Unitcode两个字段对实体进行去重处理,字段的先后顺序对最终的结果有影响

 List<CbhsXmftUnitmapEntity> cbhsXmftUnitmapEntities =new LinkedList<>();
 cbhsXmftUnitmapEntities = cbhsXmftUnitmapEntities.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(
                () -> new TreeSet<>(Comparator.comparing(o -> o.getItemCode()+ "#" + o.getUnitcode()))),
                ArrayList::new));

你可能感兴趣的:(Java)