Comparable和Comparator两种比较器详解

简介: Comparable和Comparator两种比较器详解

【1】java.lang.Comparable

Comparable,翻译一下为可比较的。从汉语词义来看,通常是表明对象特性,即该对象是可比较的。实现了该接口的类的实例对象就可以进行自然排序,该实例对象的集合或者数组就可以使用Collections.sort或Arrays.sort方法进行自然排序。

接口源码如下:

package java.lang;
import java.util.*;
public interface Comparable<T> {
    int compareTo(T var1);
}

实现了该接口的类实例对象可以作为SortedMap的key或者SortedSet的元素,而无需使用一个额外的比较器-Comparator。


强烈推荐自然排序结果与equals方法保持一致(虽然不是一定的),即自然排序时两个对象相等条件为 e1.equals(e2)返回true时,e1.compareTo(e2) == 0。另外需要注意的是null对象不是任何一个类的实例对象,所以e.compareTo(null)应该抛出NullPointerException,即使e.equals(null)返回false。


如果compareTo方法与对象的equals方法比较结果不一致时 ,那么在使用SortedMap、SortedSet这类没有明确比较器的集合时就会很奇怪。尤其是将会违反集合的基本约定–根据equals方法判断集合元素是否相等。


然而并不 严格要求(x.compareTo(y)==0) == (x.equals(y))。一般说来,任何违背这个条件的实现都应该明确指出这一事实情况。


实际上,实现Comparable的所有Java核心类都具有与equals一致的自然顺序。一个例外是java.math.BigDecimal,其自然顺序等同于具有相同值和不同精度(例如4.0和4.00)的大十进制对象。


int compareTo(T var1);方法会比较两个实例对象,0表示相等,正数表示大于,负数表示小于。

实现该方法一定要注意以下事项:


必须保证sgn(x.compareTo(y)) ==-sgn(y.compareTo(x)) 。

必须保证比较的顺序关系是可传递的,如果x.compareTo(y)>0 而且y.compareTo(z)>0 则x.compareTo(z)>0。

如果存在x.compareTo(y)=0,则对于 z 而言,存在 sgn(x.compareTo(z)) == sgn(y.compareTo(z))。


Comparable 的典型实现:


BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较

Character:按字符的 unicode值来进行比较

Boolean:true 对应的包装类实例大于 false 对应的包装类实例

String:按字符串中字符的 unicode 值进行比较

Date、Time:后边的时间、日期比前面的时间、日期大

【2】java.util.Comparator

首先第一点不同的就是,包不同了!Comparable是在java.lang包中,而Comparator是在java.util中。


第二点不同的是Comparator被显示作为一个函数式接口,其上有@FunctionalInterface注解。其只有两个抽象方法(compare和equals)但是提供了很多默认方法和静态方法。


Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用default关键字修饰。而且Default方法只在接口中被允许使用。

Java8 中,接口中允许添加静态方法,可以直接被使用。

package java.util;
import java.io.Serializable;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.ToDoubleFunction;
import java.util.Comparators;
@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
  boolean equals(Object obj);
  default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }
//...
}

Comparator比较器可以被使用在Collections.sort或 Arrays.sort方法中允许对排序顺序进行精确控制。Comparator同样可以被使用在SortedSet、SortedMap以及对其他自身没有自然排序属性的实例对象上。


同Comparable一样,Comparator的compare方法返回结果应该与equals方法返回结果保持一致。即,c.compare(e1, e2)==0时e1.equals(e2)。


不过建议谨慎使用Comparator,因为该比较器可以强制排序与使用equals方法排序集合不一致。


实现Comparator的compare方法需要保证以下几点:


必须保证sgn(compare(x, y)) ==-sgn(compare(y, x))

必须保证比较的顺序关系是可传递的,如果compare(x,y)>0 而且compare(y,z)>0 则 compare(x,z)>0。

如果存在 compare(x,y)=0,则对于 z 而言,存在 compare(x, z)==compare(y, z)。

强烈推荐compare(x,y)方法返回结果与x.equals(y)方法返回结果保持一致。然而并不 严格要求(compare(x, y)==0) == (x.equals(y))。一般说来,任何违背这个条件的 Comparator 实现都应该明确指出这一事实情况。


使用实例如下

@Test
  public void test4(){
    List<Integer> integers=new ArrayList<>();
    integers.add(1);
    integers.add(2);
    integers.add(3);
    //匿名内部类
    integers.sort(new Comparator<Integer>() {
      @Override
      public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
      }
    });
    //lambda表达式
    integers.sort((o1,o2)->o1.compareTo(o2));
//    Comparator<Integer> integerComparator = Integer::compareTo;
    //方法引用
    integers.sort(Integer::compareTo);
    integers.sort(Comparator.comparing(Integer::intValue));
  }


目录
相关文章
|
3月前
|
Java
Comparator与Comparable有什么区别
【8月更文挑战第16天】Comparator与Comparable有什么区别
74 5
Comparable与Comparator对象比较
Comparable与Comparator对象比较
56 0
Comparable 和 Comparator的理解
Comparable是一个排序接口 此接口给实现类提供了一个排序的方法,此接口有且只有一个方法
131 0
Comparable 和 Comparator的理解
|
搜索推荐 算法 安全
浅谈Comparable和Comparator
首先我们考虑一个场景:有一个整形数组, 我们希望通过调用一个工具类的排序方法就能对该数组进行排序. 请看下面的代码:
排序Comparable 和 Comparator的区别
排序Comparable 和 Comparator的区别
112 0
|
Java
说说Comparator比较器那些用法
关于java的排序,在java8之后有了函数式接口之后,就产生了很多种Comparator比较器的写法。细数一下那些常用的比较器。
1390 1
说说Comparator比较器那些用法
Comparable与Comparator有什么区别?
Comparable与Comparator有什么区别?
222 0
关于Comparator和Comparable的理解
关于Comparator和Comparable的理解
120 0