1. 前言

最近用到了集合排序(基于 Java 8)。现在我能用 Stream 的就用 Stream ,真香!排序可以这么写:

List<People> peoples = new ArrayList<>();
// 中间省略
// 按照年龄从小到大排序
peoples.sort(Comparator.comparing(People::getAge));

这里排序用到了一个关键接口 java.util.Comparator。排序比较作为业务中经常出现的需求,我们有必要研究一下这个接口。

2. Comparator 概念

Comparator 是一个函数式接口。它经常用于没有天然排序的集合进行排序,如 Collections.sortArrays.sort。或者对于某些有序数据结构的排序规则进行声明,如 TreeSetTreeMap 。也就是该接口主要用来进行集合排序。

3. Comparator 中的方法

Comparator 作为一个函数式接口只有一个抽象方法,但是它有很多的默认方法,我们来认识一下这些方法们。

3.1 compare 抽象方法

作为Comparator 唯一的抽象方法,int compare(T o1,T o2) 比较两个参数的大小, 返回负整数,零,正整数 ,分别代表 o1<o2o1=o2o1>o2,通常分别返回 -101。伪表达式:

// 输入两个同类型的对象 ,输出一个比较结果的int数字
(x1,x2)-> int

实现该方法一定要注意以下事项:

  • 必须保证compare(x,y)compare(y,x) 的值的和必须为 0
  • 必须保证比较的顺序关系是可传递的,如果compare(x,y)>0 而且compare(y,z)>0compare(x,z)>0
  • 如果存在 compare(x,y)=0,则对于 z 而言,存在 compare(x, z)==compare(y, z)

然而并不 严格要求(compare(x, y)==0) == (x.equals(y))。一般说来,任何违背这个条件的 Comparator 实现都应该明确指出这一事实情况。

3.2 comparing 系列方法

Java 8 开始,Comparator 提供了一系列的静态方法,并通过函数式的风格赋予 Comparator 更加强大和方便的功能,我们暂且称它们为 comparing系列方法。

   public static <T, U> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor,
Comparator<? super U> keyComparator)
{
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(keyComparator);
return (Comparator<T> & Serializable)
(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}

该方法是该系列方法的基本方法。是不是看上去很难懂的样子?我们来分析一下该方法。它一共两个参数都是函数式接口。

第一个参数 Function<? super T, ? extends U> keyExtractor 表示输入一个是 T 类型对象,输出一个 U 类型的对象,举个例子,输入一个 People 对象返回其年龄 Integer 数值:

//   people -> people.getAge(); 转换为下面方法引用
Function<People, Integer> getAge = People::getAge;

第二个参数 keyComparator就很好理解了,表示使用的比较规则。

c1,c2 按照 第一个参数 keyExtractor 提供的规则进行提取特征,然后第二个参数keyComparator对这两个特征进行比较。下面的式子其实可以概括为 3.1(x1,x2)-> int

(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
keyExtractor.apply(c2))

Comparator & Serializable 为 Java 8 新特性:同时满足这两个类型约束

理解了这个方法后,其它该系列的方法就好理解了,这里不再赘述。目前 comparing 系列方法使用更加广泛。我们举一些例子:

List<People> peoples = new ArrayList<>();
// ………………
// 按照年龄从低到高排序
peoples.sort(Comparator.comparing(People::getAge));
// 按照年龄从高到低排序
peoples.sort(Comparator.comparing(People::getAge, (x, y) -> -x.compareTo(y)));

同样你可以使用 java.util.Collections 或者 Stream 提供的排序方法来使用Comparator

4. 小结

今天对 Comparator进行了简单的分析,它用于构建集合排序的规则,在日常开发中非常有用。下一篇 我们将对另一个和它十分相似的接口 Comparable 进行分析和比较它们的不同,敬请关注。

关注公众号:Felordcn 获取更多资讯

个人博客:https://felord.cn

Java 集合排序策略接口 Comparator的更多相关文章

  1. Java集合Map接口与Map.Entry学习

    Java集合Map接口与Map.Entry学习 Map接口不是Collection接口的继承.Map接口用于维护键/值对(key/value pairs).该接口描述了从不重复的键到值的映射. (1) ...

  2. java集合类型接口和实现类个人总结

    转载:http://blog.csdn.net/qingchunbusanchang/article/details/39576749 java的集合是一个比较综合的概念,相关的知识有很多的博客里面做 ...

  3. JAVA集合--Iterator接口

        本文首发于cartoon的博客     转载请注明出处:https://cartoonyu.github.io/cartoon-blog     上一篇文章中我在集合元素的遍历中已经有涉及到I ...

  4. JAVA集合--Collection接口

        本文首发于cartoon的博客     转载请注明出处:https://cartoonyu.github.io/cartoon-blog     在概述里面也说过:Collection是jav ...

  5. Java集合——Set接口

    1.定义 set中不允许放入重复的元素(元素相同时只取一个),使用equals()方法进行比较.如果返回true,两个对象的HashCode值也应该相等 2.方法 add():添加元素 remove( ...

  6. Java集合-07Map接口及其抽象类

    简介 前面把List基本记录完了,对于集合List,Map,Set,因为Set基于Map,故先记录Map. 这一篇主要记录Map接口及其抽象类(java version:1.8) 整体架构 参考上图, ...

  7. java集合——Collection接口

    Collection是Set,List接口的父类接口,用于存储集合类型的数据. 2.方法 int size():返回集合的长度 void clear():清除集合里的所有元素,将集合长度变为0 Ite ...

  8. Java集合——Map接口

    1.定义 Map用于保存存在映射关系<key,value>的数据.其中,key值不能重复(使用equals()方法比较),value值可以重复 2.方法 V  put(key,value) ...

  9. Java集合——List接口

    1.定义 List是Collection的子接口,元素有序并且可以重复,表示线性表. 2.方法 add(int index,Object e):在指定索引(和数组下标类似,为0,1,2....)放入元 ...

随机推荐

  1. 关于phpstorm、idea、gogland等等ide全家桶设置

    2017-08-29 16:30:55 Preferences => IDE Settings => Editor => Code Completion => Autopopu ...

  2. MySQL主从数据库配置与原理

    1.为什么要搭建主从数据库 (1)通过增加从库实现读写分离,提高系统负载能力 (2)将从库作为数据库备份库,实现数据热备份,为数据恢复提供机会 (3)根据业务将不同服务部署在不同机器同时又共享相同的数 ...

  3. thinkphp5.1生成缩略图很模糊

    缩略图一定要从大分辨率往小生成 $image->thumb(400,400,\think\Image::THUMB_CENTER)->save(Env::get('root_path'). ...

  4. 20199308《Linux内核原理与分析》第十二周作业

    一.实验简介 竞态条件是指多个线程同时访问或者操作同一块数据,运行的结果依赖于不同线程访问数据的顺序.如果一个拥有root权限的程序存在竞态条件漏洞的话,攻击者可以通过运行一个平行线程与漏洞程序竞争, ...

  5. 任意文件下载(pikachu)

    任意文件下载漏洞 很多网站都会提供文件下载功能,即用户可以通过点击下载链接,下载到链接所对应的文件. 但是,如果文件下载功能设计不当,则可能导致攻击者可以通过构造文件路径,从而获取到后台服务器上的其他 ...

  6. Spring5参考指南:基于注解的容器配置

    文章目录 @Required @Autowired @primary @Qualifier 泛型 @Resource @PostConstruct和@PreDestroy Spring的容器配置可以有 ...

  7. 2019-05-22 BTC走势分析

    转载于:https://juejin.im/post/5ce4adf5f265da1b8c195ff8

  8. Python自动化运维一之psutil

    1.1系统性能信息模块psutil 1.1.1下载安装psutil 1.   wget https://pypi.python.org/packages/source/p/psutil/psutil- ...

  9. php-fpm7 启动脚本

    [root@bbs init.d]$ cat php-fpm7 #!/bin/sh # DateTime:20170918 # Source function library. . /etc/rc.d ...

  10. vue跳转的两种方法

    1 标签跳转 <router-link to='two'><button>点我到第二个页面</button></router-link> 2 点击事件跳 ...