当前位置: 首页 > article >正文

别再手写Comparator了!用Java 8的comparingInt()让对象排序代码清爽三倍

别再手写Comparator了用Java 8的comparingInt()让对象排序代码清爽三倍还在为Java集合排序写满屏的匿名内部类而头疼每次看到new ComparatorT()就开始条件反射地烦躁是时候拥抱Java 8的函数式编程魔法了。Comparator.comparingInt()这个看似简单的方法能让你在处理对象排序时少写50%的样板代码同时让业务逻辑的呈现更加清晰直白。1. 传统排序方式的痛点与革新十年前我刚接触Java集合排序时教科书上是这么教的要么让对象实现Comparable接口要么写个Comparator匿名内部类。这两种方式在小型项目中尚可接受但当业务对象变得复杂时代码就会迅速膨胀。看看这个典型的老式写法ListEmployee employees getEmployees(); Collections.sort(employees, new ComparatorEmployee() { Override public int compare(Employee e1, Employee e2) { return Integer.compare(e1.getSalary(), e2.getSalary()); } });短短几行代码里真正有业务价值的只有getSalary()这个调用其他全是模板代码。更糟的是当需要多级排序时Collections.sort(employees, new ComparatorEmployee() { Override public int compare(Employee e1, Employee e2) { int deptCompare e1.getDepartment().compareTo(e2.getDepartment()); if (deptCompare ! 0) { return deptCompare; } return Integer.compare(e1.getSalary(), e2.getSalary()); } });这样的代码不仅冗长而且将真正的业务逻辑淹没在了语法噪声中。Java 8的Comparator.comparingInt()等静态方法正是为解决这些问题而生。2. comparingInt()的核心用法解析Comparator.comparingInt()是Java 8中Comparator接口新增的静态方法其方法签名如下static T ComparatorT comparingInt(ToIntFunction? super T keyExtractor)这个方法接受一个函数式接口ToIntFunction它会从对象中提取一个int类型的排序键。返回的Comparator会根据这个键进行自然序升序排序。让我们用实际的例子来感受它的威力。假设有个Product类class Product { private String name; private int stock; private double price; // 构造方法和getter省略 }要对商品列表按库存量排序现在只需要ListProduct products getProducts(); products.sort(Comparator.comparingInt(Product::getStock));对比传统写法代码量减少了60%而且意图一目了然按库存量排序。这种表达方式更接近自然语言可读性大幅提升。2.1 处理基本类型与包装类型comparingInt()专门用于处理int类型字段避免了自动装箱的开销。对于其他基本类型Java 8也提供了对应的方法方法名适用类型示例comparingIntintcomparingInt(Product::getStock)comparingLonglongcomparingLong(User::getId)comparingDoubledoublecomparingDouble(Product::getPrice)对于对象类型的字段如String则使用通用的comparing方法products.sort(Comparator.comparing(Product::getName));3. 高级排序技巧实战真正的业务场景往往比简单的单字段排序复杂得多。Java 8的Comparator系列方法可以优雅地处理这些情况。3.1 多级排序当主要排序字段相同时我们需要指定次要排序字段。传统写法需要手动处理if-else分支而Java 8提供了thenComparing方法链// 先按价格排序价格相同再按库存排序 products.sort(Comparator.comparingDouble(Product::getPrice) .thenComparingInt(Product::getStock));这种写法不仅简洁而且每个排序条件的优先级一目了然。如果需要三级排序继续链式调用即可products.sort(Comparator.comparing(Product::getCategory) .thenComparingDouble(Product::getPrice) .thenComparingInt(Product::getStock));3.2 降序排序默认情况下这些比较器都是升序排列。要改为降序只需在链式调用中加入reversed()// 价格从高到低排序 products.sort(Comparator.comparingDouble(Product::getPrice).reversed());对于多级排序可以灵活控制每一级的排序方向// 类别升序价格降序库存升序 products.sort(Comparator.comparing(Product::getCategory) .thenComparingDouble(Product::getPrice).reversed() .thenComparingInt(Product::getStock));3.3 处理null值现实中的数据往往不完美字段可能为null。Java 8提供了nullsFirst和nullsLast来处理这种情况// null值排在最后 ComparatorProduct nullSafeComparator Comparator.nullsLast(Comparator.comparing(Product::getName)); products.sort(nullSafeComparator);也可以组合使用// 先按可能为null的部门排序(null排前)部门相同再按非null的薪资排序 employees.sort(Comparator.comparing(Employee::getDepartment, Comparator.nullsFirst(String::compareTo)) .thenComparingInt(Employee::getSalary));4. 在数据结构中的实际应用这些比较器不仅适用于Collections.sort()还能用于各种需要比较器的场景让整个代码库保持一致的简洁风格。4.1 优先队列(PriorityQueue)创建自定义排序的优先队列变得异常简单// 按商品价格的小顶堆 PriorityQueueProduct cheapProducts new PriorityQueue( Comparator.comparingDouble(Product::getPrice)); // 按员工薪资的大顶堆 PriorityQueueEmployee topEarners new PriorityQueue( Comparator.comparingInt(Employee::getSalary).reversed());4.2 TreeMap/TreeSet自定义排序的TreeMap// 按产品名称长度排序的TreeMap MapProduct, Integer productMap new TreeMap( Comparator.comparingInt(p - p.getName().length()));4.3 Stream API中的排序与Stream API配合使用时代码更加流畅ListString topExpensiveProductNames products.stream() .sorted(Comparator.comparingDouble(Product::getPrice).reversed()) .limit(10) .map(Product::getName) .collect(Collectors.toList());5. 性能考量与最佳实践虽然lambda表达式和函数式编程带来了代码简洁性但在性能关键路径上仍需注意避免重复创建比较器对于频繁使用的比较器应该静态缓存private static final ComparatorProduct PRODUCT_STOCK_COMPARATOR Comparator.comparingInt(Product::getStock); // 使用时 products.sort(PRODUCT_STOCK_COMPARATOR);方法引用vs lambda优先使用方法引用它通常更高效且更清晰// 推荐 Comparator.comparingInt(Product::getStock) // 不推荐 Comparator.comparingInt(p - p.getStock())复杂比较器的可读性当比较逻辑非常复杂时适当拆分ComparatorEmployee complexComparator Comparator .comparing(Employee::getDepartment) .thenComparing(e - e.getTeam().getName()) .thenComparingInt(Employee::getYearsOfService) .thenComparing(Employee::getName);测试注意事项排序逻辑变更时务必补充测试用例验证边界条件Test void testProductSorting() { Product p1 new Product(A, 100, 9.99); Product p2 new Product(B, 50, 5.99); Product p3 new Product(C, 100, 7.99); ListProduct products Arrays.asList(p1, p2, p3); products.sort(Comparator.comparingInt(Product::getStock) .thenComparingDouble(Product::getPrice)); assertEquals(B, products.get(0).getName()); assertEquals(C, products.get(1).getName()); assertEquals(A, products.get(2).getName()); }6. 常见问题与解决方案在实际项目中应用这些技巧时可能会遇到一些典型问题Q1如何处理自定义的比较逻辑对于非标准的比较逻辑可以使用comparing()的重载版本传入自定义的比较器// 按产品名称长度排序 products.sort(Comparator.comparing(Product::getName, Comparator.comparingInt(String::length)));Q2原始类型数组如何优雅排序对于int[]、long[]等原始类型数组Java 8也提供了改进int[] numbers {3, 1, 4, 2}; Arrays.parallelSort(numbers); // 多线程排序Q3如何调试复杂的比较器链可以在比较器链中插入peek操作来观察中间状态ListProduct sorted products.stream() .sorted(Comparator.comparing(Product::getCategory) .thenComparingDouble(p - { System.out.println(Comparing price of p.getName()); return p.getPrice(); })) .collect(Collectors.toList());Q4为什么我的比较器不能序列化如果需要序列化比较器确保所有涉及的lambda和方法引用都可序列化// 可序列化的比较器 ComparatorProduct serializableComparator (ComparatorProduct Serializable)Comparator.comparingInt(Product::getStock);7. 从comparingInt看Java 8编程范式comparingInt()不仅仅是一个工具方法它代表了Java 8引入的全新编程范式声明式编程关注做什么而非怎么做函数组合通过方法链构建复杂行为代码即文档方法名直接表达意图这种风格的代码更容易适应需求变化。比如当排序规则需要从按价格改为按折扣率只需修改一处// 修改前 products.sort(Comparator.comparingDouble(Product::getPrice)); // 修改后 products.sort(Comparator.comparingDouble(Product::getDiscountRate));相比之下传统写法需要修改匿名内部类中的实现逻辑更容易引入错误。在团队协作中采用这种一致的代码风格还能显著降低沟通成本。新成员阅读代码时一眼就能理解排序逻辑而不必费力解析冗长的匿名类实现。

相关文章:

别再手写Comparator了!用Java 8的comparingInt()让对象排序代码清爽三倍

别再手写Comparator了&#xff01;用Java 8的comparingInt()让对象排序代码清爽三倍 还在为Java集合排序写满屏的匿名内部类而头疼&#xff1f;每次看到new Comparator<T>()就开始条件反射地烦躁&#xff1f;是时候拥抱Java 8的函数式编程魔法了。Comparator.comparingIn…...

搭建智能代账平台收费乱象数据统计分析代码,收集各家平台服务费数据,核算定价差值,识别垄断高价异常区间。

“智能代账平台收费乱象统计分析”这一课题&#xff0c;这其实是一个非常有现实意义的“数据合规与反不正当竞争”场景。在智能会计领域&#xff0c;利用数据分析手段监控市场定价行为&#xff0c;正是技术赋能财务监管的典型应用。下面我将按照你的要求&#xff0c;为你构建一…...

网盘直链下载助手终极指南:八大网盘一键获取真实下载地址

网盘直链下载助手终极指南&#xff1a;八大网盘一键获取真实下载地址 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天…...

从知网导出到可视化图谱:Citespace 6.2.R4 完整分析CNKI文献的实战流程

从知网到知识图谱&#xff1a;Citespace 6.2.R4 深度分析CNKI文献的全流程解析 当你面对数百篇CNKI文献时&#xff0c;是否曾感到无从下手&#xff1f;这些密密麻麻的文字背后&#xff0c;隐藏着怎样的研究脉络和知识结构&#xff1f;Citespace作为文献计量分析的利器&#xff…...

终极指南:如何一键恢复B站经典界面,重温小电视播放器的美好时代

终极指南&#xff1a;如何一键恢复B站经典界面&#xff0c;重温小电视播放器的美好时代 【免费下载链接】Bilibili-Old 恢复旧版Bilibili页面&#xff0c;为了那些念旧的人。 项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Old 你是否怀念那个简洁明了的B站界面…...

告别踩坑!Windows 10/11 保姆级安装SQL Server 2012全流程(附常见报错解决方案)

Windows 10/11 实战指南&#xff1a;SQL Server 2012 完美安装与深度排错 在数字化转型浪潮中&#xff0c;数据库技术依然是企业信息系统的核心支柱。尽管SQL Server 2012已不是最新版本&#xff0c;但仍有大量传统系统依赖这一经典平台。本文将带您穿越时空隧道&#xff0c;在…...

FPGA网络协议栈入门:从零开始,用Xilinx K7325t开发板实现一个支持DHCP和Ping的10G以太网节点

FPGA网络协议栈实战&#xff1a;基于Xilinx K7325t的10G以太网节点开发指南 引言 在当今高速网络通信领域&#xff0c;FPGA凭借其并行处理能力和低延迟特性&#xff0c;正成为构建高性能网络协议栈的理想平台。本文将带领读者从零开始&#xff0c;使用Xilinx K7325t开发板实现一…...

从零开始:NSC_BUILDER让你的Switch游戏管理事半功倍

从零开始&#xff1a;NSC_BUILDER让你的Switch游戏管理事半功倍 【免费下载链接】NSC_BUILDER Nintendo Switch Cleaner and Builder. A batchfile, python and html script based in hacbuild and Nuts python libraries. Designed initially to erase titlerights encryption…...

Rust的匹配中的编译器行为

Rust的匹配机制以其强大的安全性和灵活性著称&#xff0c;而编译器在背后的行为更是其精髓所在。匹配不仅是语法糖&#xff0c;更是编译器进行静态分析、优化和错误检查的核心工具。通过深入理解编译器如何处理匹配表达式&#xff0c;开发者可以写出更高效、更安全的代码。本文…...

从 16 亿营收的 Momcozy 看:AI Agent 怎么做海外电商战略分析

【AI Agent 电商 Ep.01】附完整 Prompt 包 5 道调研题 以 Momcozy 为例 可复用 SOP— 01 一个反常识的开场 先问你一个问题。 如果我告诉你&#xff0c;在你眼皮底下&#xff0c;有一家深圳公司——2017 年才成立、A 轮融资、深圳普通写字楼里、500 人团队——去年干出了…...

Z变换与数字滤波器设计:原理与应用

1. Z变换的数学本质与工程意义Z变换作为离散时间信号处理的核心数学工具&#xff0c;其定义式看似简单却蕴含着深刻的工程价值。给定离散时间信号x[n]&#xff0c;其Z变换定义为复平面上的解析函数&#xff1a;$$ X(z) \sum_{n-\infty}^{\infty} x[n]z^{-n} $$这个公式建立了时…...

为什么90%的团队不敢在金融核心系统启用Java 25虚拟线程?揭开3大未公开的JVM安全缺陷(含CVE-2024-XXXX临时缓解补丁)

第一章&#xff1a;Java 25虚拟线程在金融核心系统中的安全准入边界金融核心系统对一致性、可审计性与故障隔离能力具有严苛要求&#xff0c;Java 25引入的虚拟线程虽显著提升高并发I/O吞吐&#xff0c;但其轻量调度模型与传统平台线程存在本质差异&#xff0c;必须建立明确的安…...

Halcon工业视觉项目避坑:形状模板保存加载的3个常见错误与解决方案

Halcon工业视觉项目避坑&#xff1a;形状模板保存加载的3个常见错误与解决方案 在工业视觉检测项目中&#xff0c;形状模板匹配是最常用的技术之一。许多工程师在初次使用Halcon进行模板匹配时&#xff0c;往往只关注模板创建和匹配过程&#xff0c;而忽视了模板保存和加载环节…...

终极游戏自动化脚本:解放双手的完整指南

终极游戏自动化脚本&#xff1a;解放双手的完整指南 【免费下载链接】AzurLaneAutoScript Azur Lane bot (CN/EN/JP/TW) 碧蓝航线脚本 | 无缝委托科研&#xff0c;全自动大世界 项目地址: https://gitcode.com/gh_mirrors/az/AzurLaneAutoScript 想要在《碧蓝航线》中轻…...

**发散创新:基于Go语言的日志指标采集与可视化实战**在现代分布式系统中,**日志 + 指标*

发散创新&#xff1a;基于Go语言的日志指标采集与可视化实战 在现代分布式系统中&#xff0c;日志 指标已成为运维监控的核心支柱。如何高效地从服务中提取关键指标&#xff08;如请求耗时、错误率、QPS&#xff09;&#xff0c;并将其结构化存储用于后续分析&#xff1f;本文…...

终极Windows系统优化指南:使用RyTuneX实现性能提升300%的完整方案

终极Windows系统优化指南&#xff1a;使用RyTuneX实现性能提升300%的完整方案 【免费下载链接】RyTuneX RyTuneX is a cutting-edge optimizer built with the WinUI 3 framework, designed to amplify the performance of Windows devices. Crafted for both Windows 10 and 1…...

Jlink V9固件修复踩坑全记录:从‘不亮灯’到成功联机KEIL

Jlink V9固件修复实战手记&#xff1a;从硬件诊断到软件重生的完整历程 作为一名嵌入式开发者&#xff0c;Jlink调试器突然罢工的经历想必不少人都有过。那天早晨&#xff0c;当我像往常一样将Jlink V9插入电脑准备调试STM32项目时&#xff0c;熟悉的绿色指示灯没有亮起&#…...

Spring Cloud Gateway 踩坑实录:升级到2020+版本后,lb://服务名路由503?一个依赖搞定

Spring Cloud Gateway 2020版本升级指南&#xff1a;解决lb://服务名路由503问题 最近在将Spring Cloud项目从Hoxton升级到2020.0.x及以上版本时&#xff0c;不少开发者遇到了一个奇怪的问题&#xff1a;原本运行良好的Gateway路由配置突然失效&#xff0c;特别是使用lb://服务…...

终极指南:Navicat Premium macOS版无限试用重置脚本完全解析

终极指南&#xff1a;Navicat Premium macOS版无限试用重置脚本完全解析 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 对于…...

IDM试用重置工具:一键恢复30天试用期的智能解决方案

IDM试用重置工具&#xff1a;一键恢复30天试用期的智能解决方案 【免费下载链接】idm-trial-reset Use IDM forever without cracking 项目地址: https://gitcode.com/gh_mirrors/id/idm-trial-reset 还在为Internet Download Manager&#xff08;IDM&#xff09;试用期…...

DeerFlow基础教程:MCP系统与Python代码执行环境配置

DeerFlow基础教程&#xff1a;MCP系统与Python代码执行环境配置 1. 认识您的深度研究助理 DeerFlow是一个功能强大的深度研究助手&#xff0c;它能够帮您完成各种复杂的研究任务。想象一下&#xff0c;您有一个24小时待命的个人研究团队——能够搜索最新信息、分析数据、编写…...

Docker + Ray + Llama 3调度崩溃复盘(CVE-2024-35241关联漏洞预警):72小时紧急修复路径与降级备案方案

第一章&#xff1a;Docker Ray Llama 3调度崩溃事件全景速览 2024年中旬&#xff0c;多个生产级大语言模型推理平台在升级至Llama 3&#xff08;8B/70B&#xff09;并采用Ray作为分布式任务调度器、Docker容器化部署后&#xff0c;集中爆发了“调度器无响应—Worker进程静默退…...

DC-DC电源PCB布局的“玄学”与科学:从电流环路到EMI优化的底层逻辑详解

DC-DC电源PCB布局的“玄学”与科学&#xff1a;从电流环路到EMI优化的底层逻辑详解 当你在深夜调试一块DC-DC电源板时&#xff0c;是否曾遇到过这样的场景&#xff1a;明明按照手册推荐布局&#xff0c;却依然被EMI问题困扰&#xff1b;或者某个关键节点的电压波形总是出现难以…...

Translumo:3分钟学会使用这款Windows实时屏幕翻译神器,打破语言障碍

Translumo&#xff1a;3分钟学会使用这款Windows实时屏幕翻译神器&#xff0c;打破语言障碍 【免费下载链接】Translumo Advanced real-time screen translator for games, hardcoded subtitles in videos, static text and etc. 项目地址: https://gitcode.com/gh_mirrors/t…...

【Docker 27网络隔离黄金配置模板】:已验证于万级Pod集群,故障率下降92.6%

第一章&#xff1a;Docker 27网络隔离增强的演进背景与核心价值Docker 27&#xff08;即 Docker Engine v27.0&#xff09;标志着容器网络模型的一次关键跃迁。随着云原生应用向多租户、零信任和合规敏感场景深度渗透&#xff0c;传统基于 bridge 和 overlay 的网络抽象已难以满…...

告别Office依赖!用Qt和QXlsx 1.4.3独立读写Excel的保姆级教程

告别Office依赖&#xff01;用Qt和QXlsx 1.4.3独立读写Excel的保姆级教程 在跨平台应用开发中&#xff0c;处理Excel文件一直是个令人头疼的问题。传统方案依赖Office或WPS组件&#xff0c;不仅增加部署复杂度&#xff0c;在Linux服务器、嵌入式设备等环境中更是难以实现。本文…...

别再死记硬背!用华为/中兴网管实战拆解SDH复杂环网中的SNCP配置逻辑

华为/中兴SDH网管实战&#xff1a;复杂环网中SNCP配置的逻辑拆解与思维训练 在现网传输工程中&#xff0c;SDH环网拓扑的复杂性往往让工程师陷入配置命令的泥潭。当面对多个相交环、多节点业务调度时&#xff0c;盲目套用模板配置不仅效率低下&#xff0c;更可能在故障发生时导…...

从胎压学习到Flash擦除:盘点UDS 0x31服务在实车ECU中的十大应用场景

从胎压学习到Flash擦除&#xff1a;盘点UDS 0x31服务在实车ECU中的十大应用场景 当工程师在4S店为新车匹配钥匙时&#xff0c;当生产线上的ESP模块需要标定时&#xff0c;甚至当你的爱车在深夜悄悄完成OTA升级前——这些看似毫不相关的场景背后&#xff0c;都活跃着一个共同的&…...

别再傻等完整编译了!用gradlew processDebugManifest命令,30秒揪出Manifest合并错误的元凶

30秒定位Android Manifest合并冲突&#xff1a;高效调试技巧全解析 每次集成新SDK时&#xff0c;那个熟悉的红色错误提示"Manifest merger failed"总能让开发者心头一紧。传统解决方案是运行完整的gradlew build命令&#xff0c;但这意味着要浪费5-10分钟等待完整编…...

从振荡到稳定:手把手教你用Python分析运放偏置电流测量数据(附完整代码)

从振荡到稳定&#xff1a;Python自动化分析运放偏置电流的工程实践 在电子测量领域&#xff0c;运算放大器的偏置电流参数对高精度电路设计至关重要。传统手动测量方法不仅效率低下&#xff0c;面对多组开关状态和振荡数据时更易引入人为误差。本文将分享一套完整的Python数据分…...