Comparable和Comparator两种比较器详解

本篇博文环境是jdk1.8。

【1】java.lang.Comparable

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

接口源码如下:

package java.lang;
import java.util.*;

public interface Comparable {
    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中。
Comparable和Comparator两种比较器详解_第1张图片

第二点不同的是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 {

    int compare(T o1, T o2);

	boolean equals(Object obj);

 	default Comparator reversed() {
        return Collections.reverseOrder(this);
    }

//...
}

Comparable和Comparator两种比较器详解_第2张图片

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

你可能感兴趣的:(Java数据结构,Comparable,Comparator)