Java 比较器 — Comparable 与 Comparator

自然排序与比较器排序

自然排序,即按字典顺序排序(升序排序),是默认的排序方式。对于 Arrays.sort() 与 Collections.sort() 方法,如果我们不指定比较器,使用的就是自然排序,也就是按升序排序。

如果想让元素降序排列或以我们指定的方式进行排序,就需要自定义比较器了,这可以通过 Comparable 或 Comparator 接口来实现。


Comparable接口

java.lang.Comparable 接口定义的 compareTo() 方法用于提供对实现它的对象进行整体排序。Comparable 接口只有一个方法 compareTo(Object obj)。

compareTo(Object obj)方法的工作原理是返回一个 int 值:

  • 如果this < obj,返回负值
  • 如果this == obj,返回零
  • 如果this > obj ,返回正值

在 compareTo() 方法中,很多人会写成类似下面这样的形式

public int compareTo(Node n) {
    //下面这句代码是有问题的,例如当i1为正数,i2为负数时,可能会发生溢出。
    return i1 - i2;
}

为了避免发生类似的错误,应该采用三元操作符。

用户在重写 compareTo() 方法的比较逻辑时,建议最好使自然排序与 equals 方法返回的结果一致

实际上,所有实现 Comparable 接口的 系统类都具有与 equals 一致的自然排序。java.math.BigDecimal 是个例外,它的自然排序将值相等但精确度不同的 BigDecimal 对象(如 4.0 和 4.00)视为相等。

类型排序方式
Byte Short Integer Long Float Double Boolean BigInteger BigDecimal按数字大小排序
Character按 Unicode 值的数字大小排序
String按字符串中字符 Unicode 值排序
如果一个数组中的对象实现了 Compareable 接口,则对这个数组进行排序非常简单: Arrays.sort()

如果 List 实现了该接口的话 , 我们就可以调用 Collections.sort()方法(实际上调用的是Arrays.sort()方法)给他们排序。
JDK 1.8 在 List 接口中增加了 sort() 方法,调用关系链如下:

示例如下:

 List<String> list = new ArrayList<>();
 list.add("2");
 list.add("3");
 list.add("1");
 list.sort(Comparator.naturalOrder());
 System.out.println(list);

输出结果:

[1, 2, 3]

Comparator接口

实现 Comparator 接口的类必须实现实现 compare(Object o1, Object o2) 方法,返回负值、零或正值。

Comparator 接口的作用主要有下面几点:

  1. 如果类的设计师没有考虑到 Compare 的问题而没有实现 Comparable 接口,可以通过 Comparator 来实现比较算法进行排序
  2. 为了使用不同的排序标准,比如按自定义的属性进行排序。
  3. Comparator 可以看做是外部比较器,Comparable 是内部比较器。

下面是使用 Comparable 与 Comparator 接口的示例:

public class Student implements Comparable<Student> {
    private int id;
    private String name;
    private int score;
    
    private Student(int id, String name, int score) {
        this.id = id;
        this.name = name;
        this.score = score;
    }
    
    @Override
    public int compareTo(Student s) {
        return Integer.compare(id, s.id);
    }
    
    @Override
    public String toString() {
        return "ID:" + id + " Name:" + name + " Score:" + score;
    }
    
    public static void main(String[] args) {
        Student[] stu = new Student[5];
        stu[0] = new Student(2, "Luna", 100);
        stu[1] = new Student(0, "Kate", 96);
        stu[2] = new Student(1, "Harry", 95);
        stu[3] = new Student(4, "Alice", 94);
        stu[4] = new Student(3, "Iris", 92);
    
        Arrays.sort(stu);
        System.out.println("使用Comparable接口排序(按id升序):");
        System.out.println(Arrays.toString(stu));
            
        Arrays.sort(stu, (o1, o2) -> Integer.compare(o2.score, o1.score));
        System.out.println("使用Comparator接口排序(按成绩降序):");
        System.out.println(Arrays.toString(stu));
    }
}

输出结果:

使用Comparable接口排序(按id升序):
[ID:0 Name:Kate Score:96, ID:1 Name:Harry Score:95, ID:2 Name:Luna Score:100, ID:3 Name:Iris Score:92, ID:4 Name:Alice Score:94]
使用Comparator接口排序(按成绩降序):
[ID:2 Name:Luna Score:100, ID:0 Name:Kate Score:96, ID:1 Name:Harry Score:95, ID:4 Name:Alice Score:94, ID:3 Name:Iris Score:92]

内置的比较器是按照ID升序排序,如果想要按照成绩排序,Comparator 就可以实现这个功能。在上面的例子中,Comparator 采用了 Java 8 中的 Lamda 表达式实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值