Comparable和Comparator的使用详解

Comparable和Comparator介绍以及常见的问题

在实际业务开发中,常常看到使用compareTo,compare方法进行值得比较、排序,compareTo方法来自于Comparable接口,而compare方法则来自于Comparator接口,两个接口都是顶层接口。Comparable翻译为中文是“比较”的意思,而Comparator是“比较器”的意思。Comparable是以-able结尾的,表示它自身具备着某种能力,而Comparator是以-or结尾,表示自身是比较的参与者。虽然Comparable和Comparator都是用来进行元素排序的,但二者有着本质的区别,

Comparable

常见类值比较

如Integer、String、BigDecimal得比较

int c = Integer.valueOf(1).compareTo(XXX);
int s = String.valueOf(1).compareTo(YYY);
int b = BigDecimal.valueOf(1).compareTo(FFF);

当返回得值大于0,表示前面得值大于后面得值,当返回得值等于0,表示前面得值等于后面得值,当返回得值小于0,表示前的值小于后面得值。

问题1:使用compareTo方法判断两个值得是否相等有什么意义,用equals也能实现进行判断得呀?

解答:通常,仅仅知道两个值是否相同是不够的。对于排序应用来说,必须知道一个值是大于、等于还是小于另一个,从而知道先后顺序。compareTo() 方法实现了这种功能。

int compareToResult = Integer.valueOf(1).compareTo(XXX);
if(compareToResult == 0){
    do1.....
}else if(compareToResult > 0){
    do2.....
}else if(compareToResult < 0){
    do3.....
}

这显然使用equals是不能达到这种效果

问题2:当compareTo入参为null会怎么样?

解答:当compareTo入参为null时会导致空指针异常,故我们需要避免入参是null得情况

问题2:可以自定义重写compareTo吗?

解答:可以,compareTo方法其实是Java.lang.Comparable接口定义的方法,它有一个参数即要比较的对象。这个方法返回一个整数值,用于指示被比较的对象的顺序关系。如果当前对象小于要比较的对象,则返回负整数;如果当前对象等于要比较的对象,则返回0;如果当前对象大于要比较的对象,则返回正整数。返回的值用于排序和搜索等操作。

Comparable接口

public interface Comparable<T> {
     public int compareTo(T o);
}

比如String、Integer、BigDecimal都是实现了这个Comparable接口,并重写了compareTo方法

String

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
   public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
}

Integer

public final class Integer extends Number implements Comparable<Integer> {
    public int compareTo(Integer anotherInteger) {
       return compare(this.value, anotherInteger.value);
    }
    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
}

。。。

自定义类比较

如Integer、String、BigDecimal类都是继承了Comparable并重写了compareTo方法进行比较,当然我们也可以自定义类值的比较策略

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person  implements Comparable<Person>{
    private String name;
    private Integer age;
    
     @Override
    public int compareTo(Person p) {
        if(Objects.isNull(p)||Objects.isNull(p.getAge())){
            //待比较值为空,无法比较,返回 999
            return 999
        }
        return this.getAge().compareTo(p.getAge());
    }
}
public String compareToPersion(Person p1,Person p2){
    int compareAge = (Objects.isNull(p)||Objects.isNull(p.getAge())) ? 999 : p1.compareTo(p2);
    if(compareAge == 0){
        return p1.getName + "和" + p2.getName + "年龄相同!";
    }else if(compareAge > 0){
        return p1.getName + "的年龄大于!" + p2.getName;
    }else if(compareAge < 0){
        return p1.getName + "的年龄小于" + p2.getName;
    }else{
        return "数据异常,无法比较!";
    }
}

排序功能使用

自然排序

在上述,我们已经见过了Integer、String、BigDecimal等对象是实现了Comparable接口并重写CompareTo方法,可以实现自然排序,这是Java中非常重要的概念之一。所谓自然排序,就是按照对象的自然顺序进行排序

我们先看如下代码

List<String> list = new ArrayList<>();
list.add("add");
list.add("bean");
list.add("port");
Collections.sort(list);
System.out.println(list);

Collections的sort排序底层实现是什么呢?按照什么规则排序呢?

Collections的sort源码

public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }

Collections类的参数只有一个集合的sort方法,集合的T对象继承于Comparable接口,即默认使用T对象的compareTo方法进行排序。比如Integer、String、BigDecimal对象等的默认排序,当对象T未继承Comparable接口,则使用默认排序,可以追踪一下该方法的源码

自定义排序
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person  implements Comparable<Person>{
    private String name;
    private Integer age;
    
     @Override
    public int compareTo(Person p) {
        return this.getAge().compareTo(p.getAge());
    }
}
List<Person> list = new ArrayList<>();
list.add(new Person("Tom", 20));
list.add(new Person("Mike", 30));
list.add(new Person("John", 25));
Collections.sort(list, Person.AgeComparator);
System.out.println(list);

执行结果为:[Person [name=Tom, age=20], Person [name=John, age=25], Person [name=Mike, age=30]],可以看出,Person对象是按照年龄进行排序的。

Comparator

排序

Comparator和Comparable的排序方法是不同的,Comparable排序的方法是compareTo,而Comparator排序的方法是compare

List<String> list = new ArrayList<>();
list.add("add");
list.add("bean");
list.add("port");
Collections.sort(list,Comparator.comparing(String::length));
System.out.println(list);

当Collections的sort的方法,当传入Comparator类型变量时,则按照Comparator的方法排序

源码如下

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }
自定义对象排序
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;
    private int age;
    
    public static Comparator<Person> AgeComparator = new Comparator<Person>() {
        @Override
        public int compare(Person p1, Person p2) {
            return p1.age - p2.age;
        }
    };
}
List<Person> list = new ArrayList<>();
list.add(new Person("Tom", 20));
list.add(new Person("Mike", 30));
list.add(new Person("John", 25));
Collections.sort(list, Person.AgeComparator);
System.out.println(list);

执行结果为:[Person [name=Tom, age=20], Person [name=John, age=25], Person [name=Mike, age=30]],可以看出,Person对象是按照年龄进行排序的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值