Comparator Comparators Comparable Collections排序源码解析

问题引出

起初,写了一行排序代码,空指针异常。有判空思想但对nullsLast理解是错误的,于是阅读了一下相关源码。

result.sort(Comparator.nullsLast(Comparator.comparing(StationPointDataZoneVO::getDv)));

以下写法是正确的:

result.sort(Comparator.comparing(StationPointDataZoneVO::getDv, Comparator.nullsFirst(Comparator.comparing(Function.identity()))).reversed());

接下来,以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));
}
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));
}

先说下面一个,传入一个取值函数,一般情况是以某字段为依据给对象排序,如 StationPointDataZoneVO::getDv。比较自身 Function.identity() 即可。返回一个Comparator接口的具体实现,需要注意的是,比较器最终调用的方法是实现了Comparable接口的某个对象的compareTo方法。

第一个方法传入两个参数,一个取值函数,一个比较器。最终调用比较器的compare方法。
以下写法效果一样,同样使用某对象自己实现的compareTo方法。

result.sort(Comparator.comparing(StationPointDataZoneVO::getDv));
result.sort(Comparator.comparing(StationPointDataZoneVO::getDv, Comparator.comparing(Function.identity())));
result.sort(Comparator.comparing(StationPointDataZoneVO::getDv, Comparator.naturalOrder()));

Comparator.thenComparing

thenComparing有好几个方法,本质都调用的这个。

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);};
}

不难看懂,就是上一个比较器结果相等时,调用下一个比较器,可以嵌套很多层。

Comparator.naturalOrder nullsFirst nullsLast

这三个有一个共同特点,返回 Comparators类中的某个比较器实例。

NaturalOrderComparator
 enum NaturalOrderComparator implements Comparator<Comparable<Object>> {INSTANCE;@Overridepublic int compare(Comparable<Object> c1, Comparable<Object> c2) {return c1.compareTo(c2);}@Overridepublic Comparator<Comparable<Object>> reversed() {return Comparator.reverseOrder();}}
NullComparator

构造器和核心方法

NullComparator(boolean nullFirst, Comparator<? super T> real) {this.nullFirst = nullFirst;this.real = (Comparator<T>) real;
}@Override
public int compare(T a, T b) {if (a == null) {return (b == null) ? 0 : (nullFirst ? -1 : 1);} else if (b == null) {return nullFirst ? 1: -1;} else {return (real == null) ? 0 : real.compare(a, b);}
}

回到开篇的问题,为何会报空指针就不难理解,
进入到NullComparator的compare后,a和b其实是StationPointDataZoneVO对象,它确实不为null。于是调用传入的比较器的compare方法,最终调用到的是
(StationPointDataZoneVO::getDv).compareTo(StationPointDataZoneVO::getDv).
dv取值为null,于是空指针。

Comparator.reversed reverseOrder

此时牵扯进来了,另一个类,Collections。
reversed 和reverseOrder分别返回Collections定义的ReverseComparator2比较器和ReverseComparator比较器。
这两个比较器的区别是,前者用传入的比较器做翻转比较,(即compare方法参数翻转)

public int compare(T t1, T t2) {return cmp.compare(t2, t1);
}

后者直接翻转调用compareTo

public int compare(Comparable<Object> c1, Comparable<Object> c2) {return c2.compareTo(c1);
}

Comparators

此类用于支持Comparator接口,提供两个比较器NaturalOrderComparator,NullComparator

Collections

也提供了两个比较器ReverseComparator,ReverseComparator2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/204636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

再见了 shiro

前言 作为一名后台开发人员&#xff0c;权限这个名词应该算是特别熟悉的了。就算是java里的类也有 public、private 等“权限”之分。之前项目里一直使用shiro作为权限管理的框架。说实话&#xff0c;shiro的确挺强大的&#xff0c;但是它也有很多不好的地方。shiro默认的登录…

Python优雅重启谷歌游览器并过cf

python如何优雅的重启谷歌游览器&#xff1f; 代码很简单&#xff1a; import subprocesshomepage "about:blank" # 结束已经启动的谷歌游览器 subprocess.run("taskkill /f /im chrome.exe", shellTrue) # debug启动谷歌游览器 subprocess.run(["…

docker批量删除退出状态的容器

sudo docker rm $(docker ps -a -q -f statusexited)

移动云“遇见大咖”|玻色量子副总裁巨江伟:超越摩尔定律的新型计算革命

移动云MVP&#xff0c;作为产品共建专家、关键意见领袖及技术布道者&#xff0c;帮助开发者更好地了解和使用移动云。开发者社区希望携手移动云MVP&#xff0c;与开发者共生、共赢、共成长。 8月31日&#xff0c;移动云开发者社区“遇见大咖”系列活动第2期——“[量子计算]超越…

了解c++11新特性-智能指针

c智能指针概念 1 智能指针的思想--CRAII机制 RAII是Resource Acquisition Is Initialization&#xff08;wiki上面翻译成 “资源获取就是初始化”&#xff09;的简称&#xff0c;是C语言的一种管理资源、避免泄漏的惯用法&#xff0c;利用的就是C构造的对象最终会被析构销毁的…

如何在Go中编写包

包由位于同一目录中的Go文件组成,这些文件在开头具有相同的package语句。你可以从包中包含额外的功能,使程序更复杂。有些包可以通过Go标准库获得,因此与Go安装一起安装。其他可以使用Go的go get命令安装。您还可以通过使用必要的package语句在要共享代码的相同目录中创建Go…

【Vue第3章】使用Vue脚手架_Vue2_笔记

笔记 脚手架文件结构 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── HelloWorld.vue …

英语学习(衣服与服装篇)

一、购买服装 1.有关时尚的形容词 1&#xff09;有许多可用于形容 fashion 和 clothes 的形容词。 cool 酷的 stylish 时髦的 in style 时髦 fashionable 时髦的&#xff0c;流行的 2&#xff09;描述不喜欢的衣服 out of style 过时的 dre…

springboot和swagger版本不兼容问题解决

1.错误提示 org.springframework.context.ApplicationContextException: Failed to start bean documentationPluginsBootstrapper; nested exception is java.lang.NullPointerExceptionat org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLi…

Java程序员,你掌握了多线程吗?

文章目录 01 多线程对于Java的意义02 为什么Java工程师必须掌握多线程03 Java多线程使用方式04 如何学好Java多线程写作末尾 摘要&#xff1a;互联网的每一个角落&#xff0c;无论是大型电商平台的秒杀活动&#xff0c;社交平台的实时消息推送&#xff0c;还是在线视频平台的流…

ConcurrentHashMap实现线程安全原理

我们知道&#xff0c;在日常开发中使用的HashMap是线程不安全的&#xff0c;而线程安全类HashTable只是简单的在方法上加锁实现线程安全&#xff0c;效率低下&#xff0c;所以在线程安全的环境下我们通常会使用ConcurrentHashMap。 1. 初始化数据结构时的线程安全 HashMap的底…

【51单片机系列】矩阵按键扩展实验

本文对矩阵按键的一个扩展&#xff0c;利用矩阵按键和动态数码管设计一个简易计算器。代码参考&#xff1a;https://blog.csdn.net/weixin_47060099/article/details/106664393 实现功能&#xff1a;使用矩阵按键&#xff0c;实现一个简易计算器&#xff0c;将计算数据及计算结…

【Proteus仿真】【51单片机】简易计算器

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器&#xff0c;使动态数码管、矩阵按键、蜂鸣器等。 主要功能&#xff1a; 系统运行后&#xff0c;数码管默认显示0&#xff0c;输入对应的操作数进行四则运算&#x…

JavaScript <关于逆向RSA非对称加密算法的案例(附原代码)>--案例(五)

前言: 趁热打铁,标记一下RSA的算法逆向...第二篇会有详解(本篇重在过程) 正文: 废话不说,直接分析步骤图: 到了这里,可以看到在登录的时候,需要验证码(本篇不教反验证码) 下面是正题--->逆他的pwd(密码) 总结: 问题:怎么确定一个密文数据是基于什么算法做出来的呢? 答:…

当初你问我为什么选择计算机?回头现在来总结就是穷

还记得当初自己为什么选择计算机&#xff1f; 当初你问我为什么选择计算机&#xff0c;我笑着回答&#xff1a;“因为我梦想成为神奇的码农&#xff01;我想像编织魔法一样编写程序&#xff0c;创造出炫酷的虚拟世界&#xff01;”谁知道&#xff0c;我刚入门的那天&#xff0…

NAS外网访问方案

基础流程 路由器开启端口映射&#xff08;如果有猫则要配置猫为转发模式&#xff0c;由路由器直接拨号即可使用第三方程序让内网ip发布到公网上&#xff08;如果有云服务器&#xff09;需要开启防火墙端口 好用的第三方程序 FRP穿透 优点&#xff1a;开源免费&#xff0c;速…

期末速成数据库极简版【创建】(1)

目录 前言 【1】T-SQL语句创建数据库 【2】T-SQL语句删除数据库 【3】T-SQL语句创建表 完整性约束 数据类型 例子 【4】T-SQL语句修改表 【5】T-SQL语句删除表 关于数据库&#xff0c;在我们学习Linux网络编程后面会详细学习到&#xff0c;为了应付期末考试&#xff0…

[MySQL] MySQL中的内置函数

本篇文章主要是对MySQL中常见的内置函数进行了详细解释。例如有日期类函数、字符串类函数、数学类函数等等。希望本篇文章会对你有所帮助。 文章目录 一、日期类函数 1、1 使用详解 1、2 实例演示 二、字符串函数 2、1 使用详解 2、2 实例演示 三、数学函数 四、其他函数 &…

销售如何开发客户?

在销售过程中&#xff0c;开发客户是至关重要的一环。只有拥有足够的客户群体&#xff0c;才能为公司带来更多的业务机会和收入。 现如今&#xff0c;不管是哪一行竞争都十分激烈&#xff0c;特别是那些本身没有核心竞争力和核心技术的传统 to b企业&#xff0c;正处于十分尴尬…

Leo赠书活动-12期 【Java程序员,你掌握了多线程吗?】文末送书

Leo赠书活动-12期 【Java程序员&#xff0c;你掌握了多线程吗&#xff1f;】文末送书 ✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1…