在这篇文章中,您将学习如何使用Java对Map进行排序。前几日有位朋友面试遇到了这个问题,看似很简单的问题,但是如果不仔细研究一下也是很容易让人懵圈的面试题。所以我决定写这样一篇文章。在Java中,有多种方法可以对Map进行排序,但是我们将重点介绍Java 8 Stream,这是实现目标的一种非常优雅的方法。

一、什么是Java 8 Stream

使用Java 8 Streams,我们可以按键和按值对映射进行排序。下面是它的工作原理:

  1. 将Map或List等集合类对象转换为Stream对象
  2. 使用Streams的sorted()方法对其进行排序
  3. 最终将其返回为LinkedHashMap(可以保留排序顺序)

sorted()方法以aComparator作为参数,从而可以按任何类型的值对Map进行排序。如果对Comparator不熟悉,可以看本号前几天的文章,有一篇文章专门介绍了使用Comparator对List进行排序。

二、学习一下HashMap的merge()函数

在学习Map排序之前,有必要讲一下HashMap的merge()函数,该函数应用场景就是当Key重复的时候,如何处理Map的元素值。这个函数有三个参数:

  • 参数一:向map里面put的键
  • 参数二:向map里面put的值
  • 参数三:如果键发生重复,如何处理值。可以是一个函数,也可以写成lambda表达式。
  1. String k = "key";
  2. HashMap<String, Integer> map = new HashMap<String, Integer>() {{
  3. put(k, 1);
  4. }};
  5. 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的键进行排序:

  1. // 创建一个Map,并填入数据
  2. Map<String, Integer> codes = new HashMap<>();
  3. codes.put("United States", 1);
  4. codes.put("Germany", 49);
  5. codes.put("France", 33);
  6. codes.put("China", 86);
  7. codes.put("Pakistan", 92);
  8. // 按照Map的键进行排序
  9. Map<String, Integer> sortedMap = codes.entrySet().stream()
  10. .sorted(Map.Entry.comparingByKey())
  11. .collect(
  12. Collectors.toMap(
  13. Map.Entry::getKey,
  14. Map.Entry::getValue,
  15. (oldVal, newVal) -> oldVal,
  16. LinkedHashMap::new
  17. )
  18. );
  19. // 将排序后的Map打印
  20. sortedMap.entrySet().forEach(System.out::println);

看上文中第二段代码:

  • 首先使用entrySet().stream() 将Map类型转换为Stream流类型。
  • 然后使用sorted方法排序,排序的依据是Map.Entry.comparingByKey(),也就是按照Map的键排序
  • 最后用collect方法将Stream流转成LinkedHashMap。 其他参数都好说,重点看第三个参数,就是一个merge规则的lambda表达式,与merge方法的第三个参数的用法一致。由于本例中没有重复的key,所以新值旧值随便返回一个即可。

上面的程序将在控制台上打印以下内容,键(国家/地区名称)以自然字母顺序排序:

  1. China=86
  2. France=33
  3. Germany=49
  4. Pakistan=92
  5. United States=1

请注意使用LinkedHashMap来存储排序的结果以保持顺序。默认情况下,Collectors.toMap()返回HashMapHashMap不能保证元素的顺序。

如果希望按照键进行逆向排序,加入下图中红色部分代码即可。

四、按Map的值排序

当然,您也可以使用Stream API按其值对Map进行排序:

  1. Map<String, Integer> sortedMap2 = codes.entrySet().stream()
  2. .sorted(Map.Entry.comparingByValue())
  3. .collect(Collectors.toMap(
  4. Map.Entry::getKey,
  5. Map.Entry::getValue,
  6. (oldVal, newVal) -> oldVal,
  7. LinkedHashMap::new));
  8. sortedMap2.entrySet().forEach(System.out::println);

这是显示Map按值排序的输出:

  1. United States=1
  2. France=33
  3. Germany=49
  4. China=86
  5. Pakistan=92

五、使用TreeMap按键排序

大家可能都知道TreeMap内的元素是有顺序的,所以利用TreeMap排序也是可取的一种方法。您需要做的就是创建一个TreeMap对象,并将数据从HashMapput到TreeMap中,非常简单:

  1. // 将 `HashMap` 转为 `TreeMap`
  2. Map<String, Integer> sorted = new TreeMap<>(codes);

这是输出:

  1. China=86
  2. France=33
  3. Germany=49
  4. Pakistan=92
  5. United States=1

如上所示,键(国家/地区名称)以自然字母顺序排序。

欢迎关注我的博客,里面有很多精品合集

  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

恕我直言你可能真的不会java第12篇-如何使用Stream API对Map类型元素排序的更多相关文章

  1. 恕我直言你可能真的不会java第1篇:lambda表达式会用了么?

    本文配套教学视频:B站观看地址 在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应 ...

  2. 恕我直言你可能真的不会java第2篇:Java Stream API?

    一.什么是Java Stream API? Java Stream函数式编程接口最初是在Java 8中引入的,并且与lambda一起成为Java开发的里程碑式的功能特性,它极大的方便了开放人员处理集合 ...

  3. 恕我直言你可能真的不会java第4篇:Stream管道流Map操作

    一.回顾Stream管道流map的基础用法 最简单的需求:将集合中的每一个字符串,全部转换成大写! List<String> alpha = Arrays.asList("Mon ...

  4. 恕我直言你可能真的不会java第7篇:像使用SQL一样排序集合

    在开始之前,我先卖个关子提一个问题:我们现在有一个Employee员工类. @Data @AllArgsConstructor public class Employee { private Inte ...

  5. 恕我直言你可能真的不会java第6篇:Stream性能差?不要人云亦云

    一.粉丝的反馈 问:stream比for循环慢5倍,用这个是为了啥? 答:互联网是一个新闻泛滥的时代,三人成虎,以假乱真的事情时候发生.作为一个技术开发者,要自己去动手去做,不要人云亦云. 的确,这位 ...

  6. 恕我直言你可能真的不会java第8篇-函数式接口

    一.函数式接口是什么? 所谓的函数式接口,实际上就是接口里面只能有一个抽象方法的接口.我们上一节用到的Comparator接口就是一个典型的函数式接口,它只有一个抽象方法compare. 只有一个抽象 ...

  7. 恕我直言你可能真的不会java第11篇-Stream API终端操作

    一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之前 ...

  8. 恕我直言你可能真的不会java第3篇:Stream的Filter与谓词逻辑

    一.基础代码准备 建立一个实体类,该实体类有五个属性.下面的代码使用了lombok的注解Data.AllArgsConstructor,这样我们就不用写get.set方法和全参构造函数了.lombok ...

  9. 恕我直言你可能真的不会java第5篇:Stream的状态与并行操作

    一.回顾Stream管道流操作 通过前面章节的学习,我们应该明白了Stream管道流的基本操作.我们来回顾一下: 源操作:可以将数组.集合类.行文本文件转换成管道流Stream进行数据处理 中间操作: ...

随机推荐

  1. java实现土地测量

    ** 土地测量** 造成高房价的原因有许多,比如土地出让价格.既然地价高,土地的面积必须仔细计算.遗憾的是,有些地块的形状不规则,比如是如图[1.jpg]中所示的五边形. 一般需要把它划分为多个三角形 ...

  2. Java实现第十届蓝桥杯求和

    试题 A: 求和 本题总分:5 分 [问题描述] 小明对数位中含有 2.0.1.9 的数字很感兴趣,在 1 到 40 中这样的数包 括 1.2.9.10 至 32.39 和 40,共 28 个,他们的 ...

  3. Linux学习初级篇-鸟哥的Linux私房菜 基础学习篇(第四版)

    0.1.2 一切设计的起点:CPU的架构 由于CPU的内部是有一些微指令组成的,所以我们所使用的软件都是要经过CPU内部的微指令集来达成才行.那这些指令集的设计主要又被分为两种设计理念,这是目前世界上 ...

  4. ASP.NET Core 3.1 WebApi部署到腾讯云CentOS 7+Docker

    一.准备 首先需要有一台CentOS服务器,安装最新版Docker,配置镜像加速等,安装方法网上很多,下面是一些相关指令: yum install -y yum-utils device-mapper ...

  5. Kubernetes内部域名解析的那些事儿

    前言 在kubernets环境中,服务发现大都是基于内部域名的方式.那么就涉及到内部域名的解析.从1.11版本开始,kubeadm已经使用第三方的CoreDNS替换官方的kubedns作为集群内部域名 ...

  6. CMDB 和自动化运维

    目录 传统运维和自动化运维的对比 CMDB CMDB 的几种实现方式 传统运维和自动化运维的对比 1.企业中,项目的发布流程 产品经理调研需求 -->三方开会讨论(开发,产品,运维,测试) -– ...

  7. 面试官突然问我MySQL存储过程,我竟然连基础都不会!(详细)

    所有知识体系文章,GitHub已收录,欢迎Star!再次感谢,愿你早日进入大厂! GitHub地址: https://github.com/Ziphtracks/JavaLearningmanual ...

  8. 面试官:线程池如何按照core、max、queue的执行循序去执行?(内附详细解析)

    前言 这是一个真实的面试题. 前几天一个朋友在群里分享了他刚刚面试候选者时问的问题:"线程池如何按照core.max.queue的执行循序去执行?". 我们都知道线程池中代码执行顺 ...

  9. asp.net Mvc 路由详解,非常详细.

    关于路由的理解 为什么要定义路由?路由的定义在开发中的工作量非常小,但是非常重要,因为任何请求都离不开路由. 各个电商网站的 URL 使用非常灵活,都离不开路由的定义,请大家参考几家电商的 URL 如 ...

  10. Windows程序设计(2) - API-02 文件系统

    一.磁盘分区的基本概念 1.磁盘分区(Patitions): 分区就是物理存储设备分割成多个不同的逻辑上的存储设备.分区从实质上说就是对硬盘的一种格式化.当我们创建分区时,就已经设置好了硬盘的各项物理 ...