Java Comparator 实战:多字段排序、thenComparing、reversed 与 null 值处理
Java Comparator 实战:多字段排序、thenComparing、reversed 与 null 值处理排序是天天写的活,但一到「按多个字段排」就容易翻车。比如一个订单列表,要求先按金额从高到低,金额相同再按下单时间从早到晚,时间还相同按订单号排。很多人写出来的是一坨嵌套 if 的compare方法,读都读不顺,还经常把升序降序搞反。其实 Java 8 之后Comparator提供了一套链式 API,上面这个需求一行就能表达清楚。这篇把comparing、thenComparing、reversed和最容易炸的 null 处理讲透。先看笨办法为什么难维护假设有个订单类:recordOrder(Stringid,intamount,LocalDateTimecreatedAt){}要「金额降序,金额相同按时间升序」,手写compare长这样:orders.sort((a,b)-{intcmpInteger.compare(b.amount(),a.amount());// 注意 b、a 反着写才是降序if(cmp!0)returncmp;returna.createdAt().compareTo(b.createdAt());// 这里又是 a、b 正序});问题很明显:降序要靠「把参数写反」来实现,一眼看不出意图,加字段就得再嵌一层 if,时间一长没人敢动。正确写法:comparing thenComparing链式 API 让排序规则读起来跟需求描述一模一样:importjava.util.Comparator;orders.sort(Comparator.comparingInt(Order::amount).reversed()// 金额降序.thenComparing(Order::createdAt)// 金额相同,时间升序.thenComparing(Order::id)// 再相同,按 id);comparing抽取排序字段,thenComparing追加次级规则(只有前面比出相等才会用到它),reversed把当前顺序反过来。加字段就是再接一个thenComparing,清清爽爽。对基本类型有专门的方法避免装箱:comparingInt、comparingLong、comparingDouble。字段是 int 就用comparingInt,别用泛型版comparing,能省掉 Integer 的自动装箱。坑一:reversed() 到底反转了什么reversed()反转的是它前面整条链,不是某一个字段,这是最常被误解的点。看这两个的区别:// 写法 A:reversed 只作用在 amount 上吗?不是!Comparator.comparingInt(Order::amount).thenComparing(Order::createdAt).reversed();// 实际效果:金额升序→降序,时间也跟着从升序变降序!整条链全反了// 写法 B:只想 amount 降序、时间保持升序,得单独反 amountComparator.comparingInt(Order::amount).reversed()// 先把 amount 反成降序.thenComparing(Order::createdAt);// 再接时间升序记住:reversed()反转的是「到目前为止组合出来的那个 Comparator」。想让某个字段单独降序,就在那个字段的comparing后面立刻.reversed(),再往后接别的规则。如果只是想让某个thenComparing的字段降序,可以给它传第二个参数:Comparator.comparingInt(Order::amount).reversed().thenComparing(Order::createdAt,Comparator.reverseOrder());// 时间也降序坑二:字段是 null 时直接 NPE真实数据里字段为 null 太常见了。如果createdAt可能是 null,上面的代码会在比较时抛NullPointerException,因为默认的比较逻辑会去调 null 的compareTo。Comparator提供了nullsFirst和nullsLast包装器,专门处理这种情况——把 null 统一排到最前或最后:orders.sort(Comparator.comparing(Order::createdAt,Comparator.nullsLast(Comparator.naturalOrder())// null 排最后,非 null 之间自然排序));nullsLast(naturalOrder())的意思是:两个都非 null 就按自然顺序比;有 null 就把它放最后;两个都 null 算相等。想让 null 排最前就换nullsFirst。组合排序里某个字段可能为 null,也一样包一层:Comparator.comparingInt(Order::amount).reversed().thenComparing(Order::createdAt,Comparator.nullsLast(Comparator.naturalOrder()));坑三:用 Comparator 找最值,别先排序要找「金额最高的订单」,别sort完取第一个——那是O(n log n)的浪费。Stream.max/min直接收一个 Comparator,O(n)搞定:OptionalOrderrichestorders.stream().max(Comparator.comparingInt(Order::amount));// TreeMap / PriorityQueue 也能直接吃 Comparator 保持有序PriorityQueueOrderpqnewPriorityQueue(Comparator.comparingInt(Order::amount).reversed()// 大顶堆,金额最高的在队首);同一个 Comparator 既能给sort用,也能给max、PriorityQueue、TreeMap用——写一次到处复用,这也是链式 Comparator 比手写 lambda 更值的地方。小结多字段排序用comparing(...).thenComparing(...),读起来跟需求一致,加字段只需再接一段。基本类型用comparingInt/Long/Double避免装箱。reversed()反转的是它前面整条链,不是单个字段;想让某字段单独降序,就在那个字段后立刻.reversed(),或给thenComparing传reverseOrder()。字段可能为 null 时,用nullsFirst/nullsLast包一层,别让它 NPE。找最值用Stream.max/min收 Comparator,别排完序取第一个;Comparator 还能直接喂给PriorityQueue、TreeMap。一句话记忆:排序规则要「像读句子一样」链式声明出来,而 reversed 反的是「整句」不是「一个词」。

相关新闻

ZXPInstaller终极指南:3分钟搞定Adobe插件安装的免费神器 [特殊字符]

ZXPInstaller终极指南:3分钟搞定Adobe插件安装的免费神器 [特殊字符]

ZXPInstaller终极指南:3分钟搞定Adobe插件安装的免费神器 🚀 【免费下载链接】ZXPInstaller Open Source ZXP Installer for Adobe Extensions 项目地址: https://gitcode.com/gh_mirrors/zx/ZXPInstaller 还在为Adobe插件安装发愁吗?…

2026/10/5 16:04:12 阅读更多 →
OrCAD 17.4深度评测:从交互重构到约束管理,全面解析PCB设计效率革新

OrCAD 17.4深度评测:从交互重构到约束管理,全面解析PCB设计效率革新

1. 项目概述:为什么说OrCAD 17.4是效率的“分水岭”? 如果你是一名电子工程师,或者正在学习PCB设计,那么对Cadence OrCAD这个名字一定不陌生。它几乎是原理图设计和中小规模PCB布局的代名词,以其强大的功能和相对友好的…

2026/10/13 10:45:52 阅读更多 →
扣子多模态消息性能拐点预警:当图文消息加载超时率>3.7%,必须立即执行的6项JVM与CDN协同优化

扣子多模态消息性能拐点预警:当图文消息加载超时率>3.7%,必须立即执行的6项JVM与CDN协同优化

更多请点击: https://intelliparadigm.com 第一章:扣子多模态消息性能拐点预警机制解析 扣子(Dify)平台在处理多模态消息(含文本、图像、音频嵌入及跨模态对齐请求)时,随着并发量与上下文长度增…

2026/9/22 23:21:23 阅读更多 →

最新新闻

TS流PCAP分析实战:从网络抓包定位音视频卡顿根源

TS流PCAP分析实战:从网络抓包定位音视频卡顿根源

1. 项目概述:为什么你手里的TS流PCAP文件比想象中更有价值“mpeg ts pcap 文件分析”——这串词看起来像一串技术黑话,但背后藏着大量真实业务场景里被忽视的关键信息。我接触过不少网络运维、音视频开发、IoT设备调试甚至安全分析一线的同行&#xff0c…

2026/10/14 6:05:23 阅读更多 →
C语言链表排序实战:插入排序与快速排序的指针操作详解

C语言链表排序实战:插入排序与快速排序的指针操作详解

简介:链表排序是C语言学习者绕不开的实践主题,这份源码压缩包面向正在掌握指针操作、动态内存分配和基础算法的初学者,帮助理解链表节点结构与排序算法的结合方式,也适合作为数据结构课程实验后的巩固练习。包体十分精简&#xff…

2026/10/14 6:05:23 阅读更多 →
从流量焦虑到AI获客:GEO优化师2026年实战复盘

从流量焦虑到AI获客:GEO优化师2026年实战复盘

1. 从流量焦虑到AI获客:一个优化师的2026年实战复盘过去这一年,我几乎每周都要跟不同行业的企业负责人聊同一个话题:钱花得越来越多,线索却越来越水。SEM账户里点击单价翻了一倍,信息流广告的转化率跌到千分之三以下&a…

2026/10/14 6:05:23 阅读更多 →
React Native鸿蒙跨平台固定表头长列表表格:双区布局与性能优化

React Native鸿蒙跨平台固定表头长列表表格:双区布局与性能优化

1. 一个被数据压垮的真实场景:长列表表格的"阅读灾难"上个月我接手了一个移动端报表类项目的数据展示模块,技术栈是 React Native,目标是跑通鸿蒙平台。先说结论:这个模块在改造之前,几乎处于"能看但没…

2026/10/14 6:05:23 阅读更多 →
Preliminary规格书阅读指南:锁参数、避坑、做版本跟踪

Preliminary规格书阅读指南:锁参数、避坑、做版本跟踪

简介:《PLA5506-940》是飞利浦光电提供的一份初步机密级产品规格书,版本V0.8,文档编号992215900750,适合光电与激光雷达、光通信、精密传感等领域的硬件工程师、选型评估人员和采购团队参考。该PDF围绕PLA5506-940型VCSEL阵列展开…

2026/10/14 6:05:23 阅读更多 →
一条富碱性多肽的进阶之路:序列解析、合成纯化与核定位验证

一条富碱性多肽的进阶之路:序列解析、合成纯化与核定位验证

1. 从一条氨基酸序列反推蛋白身份:这条肽的“户口本”是这样查的拿到 PDGF A-Chain (194-211) 这个编号,加上后面那一串 GRPREGSKKRKRKRLKPT,我的第一反应不是急着做实验,而是先把它当成一个“嫌疑人”来审:它到底来自…

2026/10/14 6:04:23 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →