2019独角兽企业重金招聘Python工程师标准>>>

有时候我们不可避免地要实现Comparator, 好做排序之类的事情.

要比较两个整数的时候, 我一度曾经这么写:

return a - b;

多简单啊! 如果a比b大, 无疑这个东西返回正数了.

可惜啊, 现实永远比理想残酷. java的整数不是数学中的整数, 它可能溢出地!

int a = -2000000000;
int b =  2000000000;
System.out.println(a - b);
// prints "294967296"

正确的写法是:

if (a > b) {return 1;
} else if (a < b) {return -1;
} else {return 0;
}

但是, 太麻烦了哇! 好吧, 好吧, 我知道java是一门罗唆的语言艺术, 讲究如何如何啥的, 可是, 可是, 太麻烦了哇! 太麻烦了哇!

在guava里, 对所有原始类型都提供了比较的工具函数来避免这个麻烦. 比如对long, 可以用Longs.compare():

return Longs.compare(a, b);

其它, 自然还有Ints, Shorts, Floats, Doubles等等, 就不骗字数了.

下面看一个简单的model类:

class Person {final String firstName;final String lastName;final int age;
}

下面我来实现一个Comparator, 按照名字然后年龄排序:

class PersonComparator implements Comparator<Person> {@Override public int compare(Person p1, Person p2) {int result = p1.firstName.compareTo(p2.firstName);if (result != 0) {return result;}result = p1.lastName.compareTo(p2.lastName);if (result != 0) {return result;}return Ints.compare(p1.age, p2.age);}
}

算中规中矩吧? 嗯, 就是觉得有点罗唆 (好啦, 好啦, "java是一门罗唆的语言艺术", 你好罗唆啊!). 要是能直接就说: 按firstName, lastName, age比较就好了.

有一种做法是把这些东西存到一个List<Comparable>然后用一个Comparator<List>来比较:

Ordering.natural().lexicographical().compare(Arrays.asList(p1.firstName, p1.lastName, p1.age),Arrays.asList(p2.firstName, p2.lastName, p2.age));

但是这个东西有点步骤过多, 而且, 自动box那个int, 以及创建两个临时List对象, 都似乎有点过了, 毕竟, Comparator往往是被调用多次来排序很多对象的.

对此, guava有一个相当聪明的解决办法, 用 ComparisonChain:

class PersonComparator implements Comparator<Person> {@Override public int compare(Person p1, Person p2) {return ComparisonChain.start().compare(p1.firstName, p2.firstName).compare(p1.lastName, p2.lastName).compare(p1.age, p2.age).result();}
}

这个东西的原理哪, 就是利用多态, 当p1.firstName比p2.firstName大的时候, 后续的compare()函数都是空的, 直接返回, 尽量节省计算.
另外, 因为它对所有原始类型都做了重载, 所以也不会付装箱的代价.

(个人意见, 不代表组织认可: 这个start()函数有点别扭. ComparisonChain应该提供静态compare()方法, 这样客户端就可以省去那个讨厌的start())

对了, 刚才在例子中我实在忍不住引用了 Ordering类. 要说这个类不是做了多少了不得的事情, 它的好处是相关的功能都在一个类里面, 好找 (点一下ctrl-space, IDE的自动提示就够用了). 比较常用的几个函数:

  • natural(): 比较两个Comparable.
  • reverse(): 把当前ordering反过来, 大的变小, 小的变大.
  • compound(): 如果当前ordering比较结果是平局, 用另外一个Comparator做加时赛.
  • nullsFirst(): 把null当作最小的, 排在前面.
  • nullsLast(): null最大.
  • binarySearch(): 根据当前ordering在排序列表里二分查找.

比如, 上面如果我lastName可能为null, 然后我要把null列到后面, 我就可以写:

class PersonOrdering extends Ordering<Person> {@Override public int compare(Person p1, Person p2) {return ComparisonChain.start().compare(p1.firstName, p2.firstName).compare(p1.lastName, p2.lastName, Ordering.<Person>natural().nullsLast()).compare(p1.age, p2.age).result();}
}

这里, 既然我已经用Ordering了, 我就顺手牵羊把PersonComparator变成PersonOrdering了.

转载于:https://my.oschina.net/u/2317688/blog/599367

瓜娃系列 (6) - ComparisonChain和primitives包相关推荐

  1. Go语言自学系列 | golang标准库io包

    视频来源:B站<golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]> 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持! ...

  2. java 纳秒 格式化_Java日期时间API系列35-----Jdk8中java.time包中的新的日期时间API类应用,微秒和纳秒等更精确的时间格式化和解析。...

    通过Java日期时间API系列1-----Jdk7及以前的日期时间类中得知,Java8以前除了java.sql.Timestamp扩充纳秒,其他类最大只精确到毫秒:Java8 time包所有相关类都支 ...

  3. AWS无服务开发Lambda系列之本地上传包至Lambda

    本次演示分为2种 1.无第三方依赖包 2.有第三方依赖包 1.无第三方依赖包 创建 Lambda 用作部署程序包的 .zip 文件. 1.创建函数(myfunc)项目目录,并进入该目录 bash-4. ...

  4. 6 日期字符串转日期_Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类...

    因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...

  5. 云计算实战系列十(文件查找及包管理)

    文件查找 知识点 grep: 文件内容过滤 find : 文件查找,针对文件名 xargs 文件打包及压缩 gzip bzip2 xz unzip(了解) 1.1 命令文件 # which ls // ...

  6. java 包结构 枚举类_Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类...

    因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...

  7. Go语言自学系列 | golang标准库os包和环境相关的方法

    视频来源:B站<golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]> 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持! ...

  8. 【JAVA系列】Java中的包、类的继承、多态、抽象类与接口

    文章目录 前言 一.包及访问权限 1.什么是包? 2.如何导入包? 3.JDK中常见的包 4.包的访问控制权限 二.继承 1.继承的基本概念 2.继承时方法调用顺序 3.super和this关键字 4 ...

  9. 【Kotlin基础系列】第6章 包与导入

    源文件通常以包声明开头: package org.examplefun printMessage() { /*--*/ } class Message { /*--*/ }// -- 源文件所有内容( ...

最新文章

  1. 2020 腾讯广告算法大赛:突破高分瓶颈方案分享
  2. RocketMQ CommitLog And Index
  3. SQL Server 中数据查询注意事项
  4. HTML5本地存储 localStorage
  5. 静态创意和动态创意_我在22岁时学到的关于创意指导的知识
  6. 在linux下安装mongo数据库,Linux系统下安装MongoDB
  7. LeetCode 145. 二叉树的后序遍历(后序遍历总结)
  8. 建立单链表 单链表的插入_单链列表插入
  9. 解决xhost:unable to open display的问题
  10. sublime text插件emmet自定义模板
  11. Hexo多客户端同步问题
  12. 苹果Mac强大的代码编辑器:Nova
  13. SQLServer-----SQLServer 2008 R2安装
  14. (十二)JAVA springboot微服务b2b2c电子商务系统:使用Spring Cloud Sleuth和Zipkin进行分布式链路跟踪...
  15. python文本自动伪原创_现在有哪些好用的伪原创工具?
  16. ArcFace: AdditiveAngularMarginLossforDeepFaceRecognition
  17. 西数trex自动版u盘版_当移动硬盘遇上它,改变了我的生活:西数My Passport随行版...
  18. 股市前复权、后复权与不复权
  19. python中的大数据品牌运营专业公司_大数据专业有哪些就业岗位?
  20. 通过JSP页面访问Servlet

热门文章

  1. winfrom给word加水印
  2. MySQL中更新时间字段的更新时点问题
  3. 广西事业单位考试 计算机基础知识,2018年广西壮族自治区事业单位考试《公共基础知识》1000题【必考题库】.pdf...
  4. ExoPlayer在开启循环播放时 统计播放次数和索引
  5. 解密档案:CTF密码学之RSA攻击算法
  6. Composer下载以及安装
  7. android 方法映射,高通Android平台驱动层 MSM8916 键值映射方法
  8. edge打开pdf不显示印章_win10 Edge浏览器打不开pdf文件的解决方法
  9. [译] QUIC Wire Layout Specification - Introduction Overview | QUIC协议标准中文翻译(1) 简介和概述...
  10. HTML+CSS模仿百度首页(gird+flex布局)