Java List.sort()的使用 和Comparator转换器的实现原理

Java实现List集合的排序:Comparable接口、Comparator接口、stream().sorted()方法的使用 Java 提供的 List 接口继承了 Collection 接口,因此包含 Collection 中的所有方法。List 是有序集合,允许有相同的元素。ArrayList 是List 接口的一个实现类,它实现了可变大小的数值,允许所有元素,包括 null,并可以根据索引位置对集合进行快速的随机访问。Java 中的 Comparable 接口是实现对象自然排序的核心机制,Comparable 是位于 java.lang 包中的泛型接口,用于定义对象的‌自然排序规则‌。 阅读详情

我在使用List.sort()方法的自定义比较器排序的时候,想当然认为(O1,O2)->{} o1是集合中前一个元素,o2是后一个元素,返回-1是交换元素位置,1是不交换元素位置,结果我的排序正好和我想要的相反,百度了一下,发现不少讲解帖子也都是错误的,正确的结论是:

o2在o1前面,返回-1 表⽰交换o2 和 o1的顺序;
返回0 和 1都表示不交换o2 和 o1的顺序;

来看一下list.sort()的源码

java/util/ArrayList.java:1460
    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
    //预期计数,保证对数组每个元素进行排序
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
        //预期计数与数组大小不符的话,就抛出一个并发修改异常
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

再点进去

java/util/Arrays.java:1503
public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                Comparator<? super T> c) {
        if (c == null) {
        //没有传比较器的情况,使用默认sort排序
            sort(a, fromIndex, toIndex);
        } else {
            rangeCheck(a.length, fromIndex, toIndex);
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, fromIndex, toIndex, c);
            else
                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
        }
    }

再点进去rangeCheck这个方法

java/util/Arrays.java:111
arrayLength--数组长度 fromIndex--开始排序时的索引位置 toIndex--结束排序时的索引位置
private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
        if (fromIndex > toIndex) {
            throw new IllegalArgumentException(
            //开始排序时的索引位置 大于结束排序时的索引位置 抛出参数校验非法异常
                    "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
        }
        if (fromIndex < 0) {
        //数组下标越界异常
            throw new ArrayIndexOutOfBoundsException(fromIndex);
        }
        if (toIndex > arrayLength) {
        //数组下标越界异常
            throw new ArrayIndexOutOfBoundsException(toIndex);
        }
    }

再来这个LegacyMergeSort.userRequested 用户可以设置这个为true来启用传统归并排序,我们不用关心这个
然后看 TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
点进去

java/util/TimSort.java:210
    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen) {
                         //断言 当这个返回false是会从这里停止执行代码
                         //
        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;

        int nRemaining  = hi - lo;
        //数组大小为0或者1不需要排序
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a "mini-TimSort" with no merges
        //32 代表数组长度小于此值的时候使用 mini-TimSort 排序
        if (nRemaining < MIN_MERGE) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }

        /**
         * March over the array once, left to right, finding natural runs,
         * extending short natural runs to minRun elements, and merging runs
         * to maintain stack invariant.
         */
        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
        int minRun = minRunLength(nRemaining);
        do {
            // Identify next run
            int runLen = countRunAndMakeAscending(a, lo, hi, c);

            // If run is short, extend to min(minRun, nRemaining)
            if (runLen < minRun) {
                int force = nRemaining <= minRun ? nRemaining : minRun;
                binarySort(a, lo, lo + force, lo + runLen, c);
                runLen = force;
            }

            // Push run onto pending-run stack, and maybe merge
            ts.pushRun(lo, runLen);
            ts.mergeCollapse();

            // Advance to find next run
            lo += runLen;
            nRemaining -= runLen;
        } while (nRemaining != 0);

        // Merge all remaining runs to complete sort
        assert lo == hi;
        ts.mergeForceCollapse();
        assert ts.stackSize == 1;
    }

首先看第一个 countRunAndMakeAscending

java/util/TimSort.java:347
    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
                                                    Comparator<? super T> c) {
        assert lo < hi;
        int runHi = lo + 1;
        if (runHi == hi)
            return 1;

        // Find end of run, and reverse range if descending
        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
                runHi++;
            reverseRange(a, lo, runHi);
        } else {                              // Ascending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
                runHi++;
        }

        return runHi - lo;
    }

主要看这里这里就是使用我们传入的比较器的地方了
c.compare(a[runHi++], a[lo]) ,a[runHi++]这个就是o1, a[lo] 就是o2
然后看这句int runHi = lo + 1; 既可以得出o1是在o2后的
再看这个 c.compare(a[runHi++], a[lo]) < 0 这是我们返回-1的时候了
runHi < hi && c.compare(a[runHi], a[runHi - 1] <0 这是找出到最后比较索引compare结果小于0的连续区间

   private static void reverseRange(Object[] a, int lo, int hi) {
        hi--;
        while (lo < hi) {
            Object t = a[lo];
            a[lo++] = a[hi];
            a[hi--] = t;
        }
    }

反转上述找出的区间的元素
runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0 就是不反转了

看完源码,和我们的结论一致

这是倒序
(o1,o2)->
    {
        if (o1 > o2) {
            return -1;
        } else {
            return 1;
        }
    }
这是正序
(o1,o2)->
    {
        if (o1 > o2) {
            return 1;
        } else {
            return -1;
        }
    }
Java sort用法详解(二维数组排序,List<>排序,lambada表达式,自定义类型排序) 本文章详细介绍了JAVA当中sort常用排序(一维数组逆序,二位数组排序,List排序,自定义类型排序,lambada简写)的用法,具体要怎么实现Comparator接口怎么比较都有给出实例代码和理论解释供大家参考,结果均检查无误,希望对友友有所帮助。 阅读详情

相关推荐

Java Lambda不是语法糖:行为抽象与函数式接口工程实践

Lambda表达式是Java中实现行为抽象的核心机制,其本质并非简化代码的语法糖,而是依托函数式接口(Functional Interface)构建的契约化编程模型。它通过编译期类型推断、签名匹配与invokedynamic动态链接,在运行时生成轻量级实现类,从而解耦逻辑声明与执行细节。技术价值在于提升可测试性、支持高阶组合(如Predicate.and)、强化Null安全与延迟计算能力。典型应用场景包括Stream数据处理、业务规则动态装配、Spring Boot函数式配置及单元测试回调模拟。本文聚焦ja

weixin_34014555的博客 301

java8List.sort()排序常用方法

对于一些普通的数据类型(比如 String, Integer…),它们默认实现了Comparable 接口,实现了 compareTo 方法,我们可以直接使用。 而对于一些自定义类,它们可能在不同情况下需要实现不同的比较策略,我们可以使用特定的 Comparator 实现进行比较

沛哥儿的专栏 3万+

【信息科学与工程学】计算机科学与自动化——第一百五十五篇 缓存系统设计02

编号176-190共15个条目,覆盖了缓存互连网络(环形/交叉开关)、硅光互连、散热设计、3D封装TSV、信号完整性、冗余设计、老化补偿、电磁兼容、时钟分布、JTAG测试、安全硬件、调试探针、容错路由、体偏置、共振时钟。:编号161-175共15个条目,聚焦于缓存硬件设计与配置,涵盖了MESI协议、多级TLB、分支预测BTB/BHT、自适应预取引擎、ECC纠错汉明码、路分区硬件、非暂时性存储旁路、缓存冲刷指令、缓存锁定、压缩硬件、嗅探过滤器、虚拟化EPT、QoS限速、内置自测BIST、电源管理DVFS。

weixin_49199313的博客 174

【Java 8 新特性】Java List sort() 排序示例 | 列表自定义排序

@[TOC](Java List sort() 排序示例 | 列表自定义排序) sort是java.util.List接口的默认方法。 List的排序方法在Java 8中被引入。 1. 排序方法接受比较器作为参数,并根据指定的比较器对这个列表进行排序。 default void sort(Comparator<? super E> c) 2. 如果List中的元素是可比较的,即元素类实现了Comparable接口,那么我们可以把null传给sort方法,排序将按照自然排序进行。 3. 列表不

猫巳的博客 2万+

Kill5.37版本下,使用ARMcomplier6编译__asm 函数报错的问题

Kill5-5.37版本下,使用ARMcomplier6编译__asm 函数报错的问题 问题简要描述: 昨日更新了keil5软件的版本,从5.17更新到了5.37版本,然后编译STM32项目文件时,软件提示编译报错。报错问题如下: Build started: Project: QKsoftware *** Using Compiler 'V6.18', folder: 'E:\MDK-ARM\ARM\ARM\ARMCLANG\Bin' Build target 'QKsoftware' compiling

weixin_43644424的博客 1万+

华大HC32F460 TCP Server实验

华大HC32F460 TCP Server实验

ZhuoWuKeJi的博客 1270

Java 关于List接口中sort()方法的使用

直接进入正题 sort,顾名思义,排列的意思 List接口中,sort方法时这样定义的: default void sort(Comparator&lt;? super E&gt; c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator&lt...

Atimynyc的博客 2万+

DANN实战:用Python手把手教你实现对抗迁移学习(附完整代码)

本文通过Python实战教程,手把手教你实现DANN对抗迁移学习模型,以解决领域偏移问题。文章详细解析了领域对抗神经网络的核心机制,包括梯度反转层和领域判别器的构建,并提供了从数据准备、模型搭建到训练评估的完整代码,帮助开发者快速掌握这一强大的无监督领域自适应技术。

net55的博客 317

从入门到实战:Java 函数式编程与高级工具类全解析

本文系统介绍了Java8函数式编程的核心内容。首先讲解了函数式接口的定义和四大核心接口(Supplier、Consumer、Function、Predicate)的用法及典型场景。然后通过代码示例展示了Comparator接口实现灵活排序和Arrays工具类的数组操作方法。最后介绍了反射动态创建对象的实现原理。文章强调掌握这些函数式编程特性对于编写优雅高效的现代Java代码的重要性,是理解StreamAPI和框架底层的基础。

2303_79635409的博客 401

机械工程师如何用Codex实现CAD自动化:从重复劳动到智能设计

在机械设计领域,CAD二次开发长期面临学习门槛高、维护成本大的难题。随着AI编程助手如Codex的出现,通过自然语言生成可执行代码,工程师无需精通编程即可实现图纸批量处理、BOM表自动生成、参数化建模等任务。这种技术将重复性操作自动化,显著提升设计效率,让工程师聚焦于核心创新。应用场景涵盖批量修改图纸属性、跨软件数据流转、自动打印等。本文分享机械工程师利用Codex落地自动化的实战经验与避坑指南。

weixin_32296621的博客 356

73、结合无人机进行rk3588oak-lite跟踪目标物体进行识别、跟踪

搭建仿真转换模型环境,主要python版本和我下载的rknn2的版本。截取shape节点,输出模型。so库也要对应转模型的whl。其中安装的whl版本。

sxj731533730 1623

BeanUtils优雅拷贝List:从原理到实战方案全解析

在Java开发中,对象属性拷贝是高频操作,而集合批量转换往往缺乏优雅方案。BeanUtils作为经典工具类,其copyProperties方法仅支持单对象拷贝,面对List场景需结合Stream流式处理,通过Class参数显式传入目标类型,实现安全高效的批量转换。这种基于反射的转换方式在数据量较小时表现良好,但需注意浅拷贝带来的嵌套对象共享问题。当转换逻辑复杂或性能敏感时,可引入MapStruct在编译期生成映射代码,从根本上避免反射开销。理解拷贝原理、区分浅拷贝与深拷贝,并合理选型,是提升DTO转换质量与

weixin_34372728的博客 381

OpenClaw第2章:快速安装

本章将手把手教你安装 OpenClaw。

Maynor的博客 3236

Java函数式接口本质与四大核心分类详解

函数式接口是Java类型系统中对单抽象方法接口的语义强化机制,其核心原理在于编译期通过@FunctionalInterface注解确立目标类型(Target Type),支撑Lambda表达式的类型推导与invokedynamic字节码优化。这一机制不仅保障了行为契约的类型安全,更成为Stream API、Optional和CompletableFuture等现代Java核心库的底层基石。技术价值体现在提升代码可读性、降低协作成本、支持声明式编程范式;典型应用场景涵盖数据流处理、空值防御、异步任务编排及高阶

weixin_34026276的博客 305

基于YOLOv11的建筑图纸物体检测系统设计与实现

包含多种建筑平面图,标注了墙体、门窗等元素:CAD格式的建筑图纸数据集:专门针对建筑元素的标注数据集自定义数据集:使用LabelImg等工具自行标注的建筑图纸本文以FloorPlanDataset为基础,结合部分自定义标注数据构建混合数据集。wall (墙体)door (门)window (窗)stair (楼梯)furniture (家具)text (文字标注)dimension (尺寸标注)column (柱子)

YOLO 536

多智能体强化学习算法【三】【QMIX、MADDPG、MAPPO】

相关文章: 1.QMIX算法简述 QMIX是一个多智能体强化学习算法,具有如下特点: 1. 学习得到分布式策略。 2. 本质是一个值函数逼近算法。 3. 由于对一个联合动作-状态只有一个总奖励值,而不是每个智能体得到一个自己的奖励值,因此只能用于合作环境,而不能用于竞争对抗环境。 4. QMIX算法采用集中式学习,分布式执行应用的框架。通过集中式的信息学习,得到每个智能体的分布式策略。 5. 训练时借用全局状态信息来提高算法效果。是后文提到的VDN方法的改进。 6. 接上一条,QMIX设计一个神经网络来

丨汀、的博客 5470

后端异构数据转换实战:从“不吃”到布尔值的规则引擎设计

在系统集成与数据同步场景中,异构数据源的类型映射是后端开发的核心挑战之一。其原理在于外部系统常采用非标准的字符串(如“不吃”、“N/A”)表示业务状态,而内部系统需将其转换为类型安全的布尔值或枚举。这一过程的技术价值在于保障数据一致性、提升系统健壮性,并避免硬编码带来的维护负担。通过设计可配置的规则引擎,开发者能系统化地处理语义模糊的字段,例如将“不吃”、“不要”映射为false,将“吃”、“要”映射为true。该方案适用于第三方API对接、老旧系统迁移及多源数据清洗等应用场景,最终构建出高可维护的数据处理

weixin_34122604的博客 482

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java全栈开发面试核心挑战与实战技巧

Java全栈开发要求开发者具备从JVM原理到前端框架的完整技术栈理解。在JVM层面,需要掌握内存模型、垃圾回收机制以及并发编程的核心原理,如ConcurrentHashMap的分段锁演进和ThreadLocal的内存泄漏防范。Spring Boot作为Java生态的核心框架,其自动装配机制和条件注解是面试高频考点,同时需要理解WebSocket的实战应用与问题解决。在前端领域,Vue3的组合式API和JSX的合理使用体现了技术深度。全栈调试与性能优化涉及跨进程调用链路追踪和Redis缓存穿透防御等关键技术。

weixin_34354945的博客 623

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

工作中使用到的单词(软件开发)

1.エイリアス   alias 别名 powershell使用 get-help 命令时,会得到与此命令 相关(别名)的命令 2.プロキシ proxy 代 理 3.プロモート   promote 促进,提升   开发的系统新功能上线发布,有时会使用到这个词,比如 STプロモート 还有使用リリース这个词的。比如STリリース。个人认为两者含义相同。 4.見逃し み................................................................

sun0322 6万+

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

java list排序的三种方式

1.使用 Collections 工具类中的 sort() 方法   参数不同: void sort(List list)在自定义类User里面实现Comparable<User>接口,并重写抽象方法compareTo(Student o);         void sort(List list, Comparator c) 第二个参数为了省事,可以直接使用匿名内部类 //studentsList本身元素会改变 studentsList.sort(Com.

qq_31459039的博客 3526

java中的list.sort()使用方法(底层调用Arrays.sort())

引子 我这里有一个Student类,类里只有姓名和成绩两个属性,如图 创建一个存储Student对象的List 我现在想让List中的Student对象按成绩降序排列,需先实例化 Comparator 接口,实现其中的 compare(T o1, T o2) (此处T可替换为任一引用类型)方法,该方法返回值类型为Int 在 list.sort() 底层代码中,以 compare(list [ i - 1 ], list [ i ]) 形式调用该方法, 当其的返回值大于0时,list [ i - 1 ]

qq_46121425的博客 1万+

Java中List排序的3种方法!

Java中List排序的3种方法!

看一点点书,懂一点点道理,过好这一生 2602

List按指定规则排序的四种方法

使用Collections.sort(list)可对一个List对象进行升序排序,但如果要按某种指定规则进行排序,可使用如下四种方法: ### 1. 使用list.sort(comparator)方法 List的sort()方法中可以传入一个自定义Comparator比较器。实现Comparator接口,**重写compare方法**来定义排序规则。 - 如果compare()方法返回负整数,表示obj1小于obj2; - 如果compare()方法返回零,表示obj1等于obj2; - 如果compare

m0_56602092的博客 1万+

java8List.sort()排序功能

//按照List中对象的id属性升序 list.sort(Comparator.comparing(Stu::getId)) //按照List中对象的id属性降序 list.sort(Comparator.comparing(Stu::getId).reversed()); //多条件升序 list.sort(Comparator.comparing(Stu::getId).thenCompari...

gmlic的博客 8万+

Java List sort() 排序

排序方法接受比较器作为参数,并根据指定的比较器对这个列表进行排序。

loveLifeLoveCoding的博客 1358

Java 数组排序 sort,Comparator实现排序/学生身高体重排序 /

java comparator的用法,#JavaComparator的用法##1.引言在Java中,Comparator接口是用来定义两个对象的比较规则的,它可以实现对对象的排序和定制化排序。需要注意的是,对于自定义的对象进行排序,对象需要实现 Comparable 接口或者提供 Comparator 接口的实现。在上述代码中,我们使用Collections.sort方法对list进行排序,第一个参数是要排序的list,第二个参数是Comparator对象。// 若身高和体重都相同,维持原有的编号顺序。

weixin_45600395的博客 2369
上一篇: EasyExcel实现复杂导入 适用于导入1对N类型数据如组合商品,订单和订单明细等等
下一篇: MyqlSql复杂排序 针对同一个字段根据不同条件分别做正序和倒序
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值