Java 8 Stream统计爱好学生数及排序相关技术咨询
Java Stream 爱好统计与排序问题解析
一、先修正统计学生数量的代码
你当前的collect8代码计算的是爱好对应学生的ID总和,而不是学生数量,这和你想要的统计需求不符。正确的统计每个爱好的学生数应该这样写:
// 用counting()统计数量,返回Long类型 Map<String, Long> hobbyCountMap = data.stream() .flatMap(student -> student.getHobbies().stream()) .collect(Collectors.groupingBy( hobby -> hobby, Collectors.counting() ));
或者用summingInt返回Integer类型:
Map<String, Integer> hobbyCountMap = data.stream() .flatMap(student -> student.getHobbies().stream()) .collect(Collectors.groupingBy( hobby -> hobby, Collectors.summingInt(h -> 1) ));
这样得到的才是cricket=4、football=5这类符合需求的统计结果。
二、问题1:排序后结果未按值排序的原因
你用Collectors.toMap()收集排序后的元素时,默认返回的是HashMap——这是一个无序集合,它不会保留Stream排序后的顺序,所以你看到的结果始终是混乱的。
要解决这个问题,需要使用Collectors.toMap()的重载方法,指定返回LinkedHashMap——它会严格维护元素的插入顺序,这样就能保留排序后的结果了。修改后的排序代码如下:
// 按数量升序排列,如需降序可在sorted后加.reversed() Map<String, Integer> sortedHobbyCountMap = hobbyCountMap.entrySet().stream() .sorted(Map.Entry.<String, Integer>comparingByValue()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, // 处理键冲突(此处不会出现) LinkedHashMap::new // 指定返回有序的LinkedHashMap ));
这样输出的结果就会严格按照值的升序排列了。
三、问题2:能否在分组操作中直接完成排序?
严格来说,Collectors.groupingBy本身并不支持在分组过程中直接排序,因为分组的核心是按键聚合数据,排序是独立的顺序调整操作。不过我们可以把统计和排序合并成一条链式调用,不用分成两个独立的collect操作,写法如下:
// 一步完成统计+升序排序 Map<String, Integer> sortedHobbyCountMap = data.stream() .flatMap(student -> student.getHobbies().stream()) .collect(Collectors.groupingBy( hobby -> hobby, Collectors.summingInt(h -> 1) )) .entrySet().stream() .sorted(Map.Entry.comparingByValue()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new ));
这种先分组统计、再排序收集的方式效率更高,避免了先排序再分组带来的额外性能消耗。
内容的提问来源于stack exchange,提问作者Learn Hadoop
相关产品推荐
相关产品推荐

