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

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;

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

     @Override
     public 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.kler.cn/a/161543.html

相关文章:

  • OpenGL ES 共享上下文实现多线程渲染
  • 某app最新版 vmp算法分析一
  • 前端开发中常用的包管理器(npm、yarn、pnpm、bower、parcel)
  • Unity3D实现视频和模型融合效果
  • 知识图谱6:neo4j查询语句
  • 【stable diffusion部署】超强AI绘画Stable Diffusion,本地部署使用教程,完全免费使用
  • SRC挖掘漏洞XSS
  • uni-app实现返回刷新上一页
  • 基于selenium工具刷b站播放量(请谨慎使用)
  • Spring AOP从入门到精通
  • <蓝桥杯软件赛>零基础备赛20周--第9周--前缀和与差分
  • Linux 防病毒软件:CentOS有哪些付费的防病毒软件
  • Python if else条件语句详解
  • C++新经典模板与泛型编程:用成员函数重载实现is_base_of
  • java读取微信p12证书信息
  • 鸿蒙原生应用/元服务开发-Stage模型能力接口(一)
  • 【Python3】【力扣题】383. 赎金信
  • python flask Jinja2模板学习
  • elementui el-table用span-method方法对相同的列名或行名进行合并
  • 在Windows 11中,把iPhone照片和视频导出来又快又简单,无需第三方软件
  • 数据结构 图的广度优先搜索和深度优先搜索
  • 画好一张规范的原理图,这些点你可要注意了!
  • Redis RedisHelper
  • 【LeeCode】454. 四数相加 II
  • dbug_hub 错误 使用多个ILA导致
  • STM32 定时器配置步骤