Java Comparator接口学习笔记
Comparator
是一个泛型函数式接口,T
表示待比较对象的类型:
@FunctionalInterface
public interface Comparator<T> {
}
本文将主要介绍Comparator
作为函数式接口的用法。
理解下面的内容需要以下知识:函数式接口、Lambda表达式、方法引用。
1. 抽象方法
唯一的(不是重写Object方法的)抽象方法: compare
int compare(T o1, T o2)
该方法根据o1, o2的大小关系返回:负数、0、正数
该方法的比较逻辑依赖于具体的Comparator
对象,这样的Comparator
对象通过Lambda表达式或方法引用进行构造。
Comparator<String> comparator = Comparator.comparingInt(x -> x.length()); // 比较String类对象的长度,关于comparingInt下文会介绍,它返回一个Comparator对象
System.out.println(comparator.compare("Tom", "Jerry")); // -1
2. 常用静态/默认方法
① 静态方法comparing
comparing()
有两种重载的形式:
// 源码1
// 功能:根据keyExtractor从输入中提取key,然后返回一个使用key类型默认compreTo()对key进行比较的Comparator对象
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
返回值:
comparing
返回一个Comparator
对象,用于比较T
类型对象参数:
comparing
的参数keyExtractor
是一个Function
类型,它接收T
类型及T
的超类型, 返回U
类型及U
的子类型。keyExtractor
的逻辑用Lambda表达式或方法引用实现例如,输入
String
,提取其长度:Comparator<String> keyComparator = Comparator.comparing(String::length); // 从传入的String类型对象中提取(即extract) length (即key)
keyComparator.compare("Tom", "Jerry");
函数体:
- 首先,确保
keyExtractor
不是null
- 然后,返回一个Lambda表达式,该表达式对
c1
和c2
提取出来的key
进行比较 (用的是c1
和c2
类实现的compareTo()
进行比较)
- 首先,确保
// 源码 2
// 功能: 根据keyExtractor从输入中提取key,然后返回一个根据keyComparator对key进行比较的Comparator对象
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));
}
与上面类似,只不过将key
的比较逻辑由compareTo()
替换成了自定义的比较逻辑keyComparator
实例:
package Lambda.ComparatorDemo;
import java.util.Arrays;
import java.util.Comparator;
class Person {
private String fname;
private String lname;
public Person(String fname, String lname) {
this.fname = fname;
this.lname = lname;
}
public String getFname() {
return fname;
}
public String getLname() {
return lname;
}
@Override
public String toString() {
return fname + " " + lname;
}
}
public class ComparingDemo {
public static void main(String[] args) {
Person p1 = new Person("Tom", "Kenn");
Person p2 = new Person("Alice", "Zed");
Person[] persons1 = {p1, p2};
Person[] persons2 = persons1.clone();
// 依据First Name排序(用的是String类的compareTo的比较逻辑)
Arrays.sort(persons1, Comparator.comparing(Person::getFname));
System.out.println("Person1 (Sorted by first name): ");
for (Person p : persons1) {
System.out.println(p);
}
System.out.println();
// 依据First Name的长度排序
Arrays.sort(persons2, Comparator.comparing(Person::getFname, Comparator.comparingInt(String::length)));
System.out.println("Person2 (Sorted by length of first name):");
for (Person p : persons2) {
System.out.println(p);
}
}
}
② 静态方法comparingXXX()
comparingInt()
comparingDouble()
comparingLong()
与comparing
是一样的思路,只不过comparingXXX()
将comparing
中的提取出来的key
类型固定为了XXX
:
public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
}
③ 默认方法thenComparing()
thenComparing
是默认方法,需要对Comparator
对象调用,它用于将多个Comparator
结合起来实现“链式的比较”:先根据XXX比较,再根据XXX比较,...
// 源码
default Comparator<T> thenComparing(Comparator<? super T> other) {
Objects.requireNonNull(other);
return (Comparator<T> & Serializable) (c1, c2) -> {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
};
}
public class thenComparingDemo {
public static void main(String[] args) {
Person p1 = new Person("Alice", "Jessy");
Person p2 = new Person("Alice", "Ann");
Person p3 = new Person("Tom", "Smith");
Person[] persons = {p1, p2, p3};
// 先根据first name比较,再根据last name的长度比较
Comparator<Person> chainedComparator = Comparator.comparing(Person::getFname)
.thenComparing((x, y) -> (x.getLname().length() - y.getLname().length()));
// 先根据first name排序,再根据last name的长度排序
Arrays.sort(persons, chainedComparator);
for (Person p : persons) {
System.out.println(p);
}
}
}
/*
Alice Ann
Alice Jessy
Tom Smith
参考:
Java Comparator接口学习笔记的更多相关文章
- Java多线程技术学习笔记(二)
目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- java之jvm学习笔记十三(jvm基本结构)
java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...
- 20155327 java第四周学习笔记
20155327 java第四周学习笔记 五六章知识整理 1子类与父类 父类是接口或者是抽象类,子类必须继承自父类. 2子类的继承性 在Java中,通过关键字extends继承一个已有的类,被继承的类 ...
- 《深入理解Java虚拟机》学习笔记
<深入理解Java虚拟机>学习笔记 一.走近Java JDK(Java Development Kit):包含Java程序设计语言,Java虚拟机,JavaAPI,是用于支持 Java 程 ...
- Java:NIO 学习笔记-3
Java:NIO 学习笔记-3 根据 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 3. JAVA NIO 深入剖析 在讲解利用 NIO 实现通信架构之前,我们需要先来了解一下 NI ...
- Java:NIO 学习笔记-2
Java:NIO 学习笔记-2 上一篇 NIO 学习笔记-1 看了 尚硅谷 的相应教程,此处又对比看了 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 前言 在 Java 的软件设计开 ...
- Java:NIO 学习笔记-1
Java:NIO 学习笔记-1 说明:本笔记是根据bilibili上 尚硅谷 的课程 NIO视频 而做的笔记 主要内容 Java NIO 简介 Java NIO 与 IO 的主要区别 缓冲区(Buff ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
随机推荐
- WCF自寄宿实现Https绑定
一.WCF配置 1 Address 将服务端发布地址和客户端访问地址都配置为https开始的安全地址.参考如下. <add key="SrvUrl" value=" ...
- 打印pdf
#include "pdf_print_helper.h" pdf_print_helper::pdf_print_helper(){ } pdf_print_helper::~p ...
- Linux 的计划任务
Linux操作系统定时任务系统 Cron 入门 cron是一个linux下的定时执行工具,可以在无需人工干预的情况下运行作业.由于Cron 是Linux的内置服务,但它不自动起来,可以用以下的方法启动 ...
- Java 实现对文件系统的监控
在开发中经常会用到监控文件或是目录的状态,如果你还在手写轮巡扫描文件的话,那你久out了. 1. Commons io为我们提供了一套可靠.高性能的一套文件系统监控API 1.1. 需要的jar包如下 ...
- jQuery文字“橡皮圈“特效
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 也谈SpringCloud:假如 《复仇者联盟4》是一个微服务
前言 <复仇者联盟4>(下文<妇联4>) 将于4月24号上映了,漫威迷们是不是迫不及待了.我虽然不是漫威迷,没有看过相关漫画,但是电影确实一步都不落.不过我在想一个问题:假 ...
- Spring Cloud Eureka 学习记录
SpringCloud版本 <groupId>org.springframework.cloud</groupId> <artifactId>spring-clou ...
- vagrant之道(即其工作流程)
原文http://mitchellh.com/the-tao-of-vagrant The Tao of Vagrant 在安装vagrant或了解它如何工作之前,了解vagrant在实际工作环境中的 ...
- $NOIp$前的日常
嗯,一想到没准今年\(NOIp\)之后就要退役了,觉得没准这篇博客就是我OI史上的绝唱了-- \(hhh\),希望不会这样. \(12.4\) 退役了是真的233-- 居然感到一身轻松啊qwqwq \ ...
- (转)WebSocket的原理
前言:无聊逛知乎,就逛到H5的栏目去了,正好看到了关于Websocket的东西.个人是比较喜欢看这类风格的,转到博客分享,以便自己以后理解. ---------------------分割线----- ...