恕我直言你可能真的不会java第12篇-如何使用Stream API对Map类型元素排序
在这篇文章中,您将学习如何使用Java对Map进行排序。前几日有位朋友面试遇到了这个问题,看似很简单的问题,但是如果不仔细研究一下也是很容易让人懵圈的面试题。所以我决定写这样一篇文章。在Java中,有多种方法可以对Map进行排序,但是我们将重点介绍Java 8 Stream,这是实现目标的一种非常优雅的方法。
一、什么是Java 8 Stream
使用Java 8 Streams,我们可以按键和按值对映射进行排序。下面是它的工作原理:
- 将Map或List等集合类对象转换为Stream对象
- 使用Streams的
sorted()
方法对其进行排序 - 最终将其返回为
LinkedHashMap
(可以保留排序顺序)
sorted()
方法以aComparator
作为参数,从而可以按任何类型的值对Map进行排序。如果对Comparator不熟悉,可以看本号前几天的文章,有一篇文章专门介绍了使用Comparator对List进行排序。
二、学习一下HashMap的merge()函数
在学习Map排序之前,有必要讲一下HashMap的merge()函数,该函数应用场景就是当Key重复的时候,如何处理Map的元素值。这个函数有三个参数:
- 参数一:向map里面put的键
- 参数二:向map里面put的值
- 参数三:如果键发生重复,如何处理值。可以是一个函数,也可以写成lambda表达式。
String k = "key";
HashMap<String, Integer> map = new HashMap<String, Integer>() {{
put(k, 1);
}};
map.merge(k, 2, (oldVal, newVal) -> oldVal + newVal);
看上面一段代码,我们首先创建了一个HashMap,并往里面放入了一个键值为k:1的元素。当我们调用merge函数,往map里面放入k:2键值对的时候,k键发生重复,就执行后面的lambda表达式。表达式的含义是:返回旧值oldVal加上新值newVal(1+2),现在map里面只有一项元素那就是k:3。
其实lambda表达式很简单:表示匿名函数,箭头左侧是参数,箭头右侧是函数体。函数的参数类型和返回值,由代码上下文来确定。
三、按Map的键排序
下面一个例子使用Java 8 Stream按Map的键进行排序:
// 创建一个Map,并填入数据
Map<String, Integer> codes = new HashMap<>();
codes.put("United States", 1);
codes.put("Germany", 49);
codes.put("France", 33);
codes.put("China", 86);
codes.put("Pakistan", 92);
// 按照Map的键进行排序
Map<String, Integer> sortedMap = codes.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(
Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldVal, newVal) -> oldVal,
LinkedHashMap::new
)
);
// 将排序后的Map打印
sortedMap.entrySet().forEach(System.out::println);
看上文中第二段代码:
- 首先使用entrySet().stream() 将Map类型转换为Stream流类型。
- 然后使用sorted方法排序,排序的依据是Map.Entry.comparingByKey(),也就是按照Map的键排序
- 最后用collect方法将Stream流转成LinkedHashMap。 其他参数都好说,重点看第三个参数,就是一个merge规则的lambda表达式,与merge方法的第三个参数的用法一致。由于本例中没有重复的key,所以新值旧值随便返回一个即可。
上面的程序将在控制台上打印以下内容,键(国家/地区名称)以自然字母顺序排序:
China=86
France=33
Germany=49
Pakistan=92
United States=1
请注意使用
LinkedHashMap
来存储排序的结果以保持顺序。默认情况下,Collectors.toMap()
返回HashMap
。HashMap
不能保证元素的顺序。
如果希望按照键进行逆向排序,加入下图中红色部分代码即可。
四、按Map的值排序
当然,您也可以使用Stream API按其值对Map进行排序:
Map<String, Integer> sortedMap2 = codes.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldVal, newVal) -> oldVal,
LinkedHashMap::new));
sortedMap2.entrySet().forEach(System.out::println);
这是显示Map按值排序的输出:
United States=1
France=33
Germany=49
China=86
Pakistan=92
五、使用TreeMap按键排序
大家可能都知道TreeMap内的元素是有顺序的,所以利用TreeMap排序也是可取的一种方法。您需要做的就是创建一个TreeMap
对象,并将数据从HashMap
put到TreeMap
中,非常简单:
// 将 `HashMap` 转为 `TreeMap`
Map<String, Integer> sorted = new TreeMap<>(codes);
这是输出:
China=86
France=33
Germany=49
Pakistan=92
United States=1
如上所示,键(国家/地区名称)以自然字母顺序排序。
欢迎关注我的博客,里面有很多精品合集
- 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。
觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端分离RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》
- 《VUE深入浅出系列》
恕我直言你可能真的不会java第12篇-如何使用Stream API对Map类型元素排序的更多相关文章
- 恕我直言你可能真的不会java第1篇:lambda表达式会用了么?
本文配套教学视频:B站观看地址 在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应 ...
- 恕我直言你可能真的不会java第2篇:Java Stream API?
一.什么是Java Stream API? Java Stream函数式编程接口最初是在Java 8中引入的,并且与lambda一起成为Java开发的里程碑式的功能特性,它极大的方便了开放人员处理集合 ...
- 恕我直言你可能真的不会java第4篇:Stream管道流Map操作
一.回顾Stream管道流map的基础用法 最简单的需求:将集合中的每一个字符串,全部转换成大写! List<String> alpha = Arrays.asList("Mon ...
- 恕我直言你可能真的不会java第7篇:像使用SQL一样排序集合
在开始之前,我先卖个关子提一个问题:我们现在有一个Employee员工类. @Data @AllArgsConstructor public class Employee { private Inte ...
- 恕我直言你可能真的不会java第6篇:Stream性能差?不要人云亦云
一.粉丝的反馈 问:stream比for循环慢5倍,用这个是为了啥? 答:互联网是一个新闻泛滥的时代,三人成虎,以假乱真的事情时候发生.作为一个技术开发者,要自己去动手去做,不要人云亦云. 的确,这位 ...
- 恕我直言你可能真的不会java第8篇-函数式接口
一.函数式接口是什么? 所谓的函数式接口,实际上就是接口里面只能有一个抽象方法的接口.我们上一节用到的Comparator接口就是一个典型的函数式接口,它只有一个抽象方法compare. 只有一个抽象 ...
- 恕我直言你可能真的不会java第11篇-Stream API终端操作
一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之前 ...
- 恕我直言你可能真的不会java第3篇:Stream的Filter与谓词逻辑
一.基础代码准备 建立一个实体类,该实体类有五个属性.下面的代码使用了lombok的注解Data.AllArgsConstructor,这样我们就不用写get.set方法和全参构造函数了.lombok ...
- 恕我直言你可能真的不会java第5篇:Stream的状态与并行操作
一.回顾Stream管道流操作 通过前面章节的学习,我们应该明白了Stream管道流的基本操作.我们来回顾一下: 源操作:可以将数组.集合类.行文本文件转换成管道流Stream进行数据处理 中间操作: ...
随机推荐
- Java实现 LeetCode 290 单词规律
290. 单词规律 给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律. 这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非 ...
- Java实现LeetCode_0014_LongestCommonPrefix
package javaLeetCode.primary; /** * Write a function to find the longest common prefix string amongs ...
- 设计模式系列之建造者模式(Builder Pattern)——复杂对象的组装与创建
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- iOS - 多线程——GCD
什么是GCD Grand Central Dispatch(强大的调度器),是一个C语言API: 作用:多核并行运算的解决方案: GCD中有2个核心概念 ...
- 【Flutter实战】移动技术发展史
老孟导读:大家好,这是[Flutter实战]系列文章的第一篇,这并不是一篇Flutter技术文章,而是介绍智能手机操作系统.跨平台技术的演进以及我对各种跨平台技术看法的文章. 智能手机操作系统 塞班( ...
- Cypress系列(16)- 查找页面元素的基本方法
如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 前端页面代码 后面写的 Cypress ...
- pom.xml 文件详解
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
- openresty用haproxy2.0实现负载均衡
安装openresty 编译安装 yum install pcre-devel openssl-devel gcc curl wget wget https://openresty.org/downl ...
- linear-gradient,radial-gradient 渐变
一.渐变效果 -> 线性渐变 方法: background-image: linear-gradient(direction, color-stop1, color-stop2, ...); ...
- Windows 10 WSL 2.0安装并运行Docker
在Windows 10 2004版本,微软更新WSL到了2.0,WSL 2.0已经拥有了完整的Linux内核!今天来测试一下,是否可以安装docker! 一.开启WSL 以管理员运行Powershe ...