比较器的 java_Java中的比较器(排序)

“顺序“在任何一个领域里都是非常重要的一个概念,程序也不例外。不同的执行顺序,能对你的执行结果产生直接影响。

既然涉及到顺序,那就要求排序。所以本文讨论的就是排序中使用到的比较器Comparable和Comparator。

Comparable和Comparator都是java.包下的两个接口,从字面上看这两个接口都是用来做比较用的,但是jdk里面不可能定义两个功能相同的接口,所以他们肯定有不同的用处。

JDK中的Comparable和 Comparator

Comparable和Comparator接口都是为了对类进行比较,众所周知,诸如Integer,double等基本数据类型,java可以对他们进行比较,而对于类的比较,需要人工定义比较用到的字段比较逻辑。

Comparable

Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些 类是可以和自己比较的。

若一个类实现了Comparable接口,就意味着该类支持排序。实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。

此外,**实现此接口的对象可以用作有序映射中的键或有序集合中的集合,无需指定比较器。**该接口定义如下

//@since 1.2 出现得还是稍微偏晚的

public interface Comparable{//这里入参也是T 所以是自己和自己比较的//规则:this和t比较。 返回0表示两个对象相等//返回正数: this > o//返回负数: this < o

public intcompareTo(T o);

}

比如如下例子:

public static voidmain(String[] args) {

Integer[] intArr= {new Integer(2), new Integer(1), new Integer(9), new Integer(5)};

System.out.println("排序前:" + StringUtils.arrayToCommaDelimitedString(intArr)); //排序前:2,1,9,5

Arrays.sort(intArr);

System.out.println("排序后:" + StringUtils.arrayToCommaDelimitedString(intArr)); //排序后:1,2,5,9

}

Comparator

Comparator是比较接口,我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口),那么我们就可以建立一个“该类的比较器”来进行排序,这个“比较器”只需要实现Comparator接口即可。

个人认为有两种情况可以使用实现Comparator接口的方式:

对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较(大都是这种情况)

对象实现了Comparable接口,但是开发者认为compareTo方法中的比较方式并不是自己想要的那种比较方式

//@since 1.2 JDK8该接口增加了很多默认方法,后面也会讲解

@FunctionalInterfacepublic interface Comparator{intcompare(T o1, T o2);booleanequals(Object obj);

}

若一个类要实现Comparator接口:它一定要实现compare(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。

int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。

现在我们自定义一个类Person,然后给Person类自定义一个比较器。

public classPerson {publicString name;publicInteger age;

}//person类的Compartor比较器 泛型类型为Person//按照

public class PersonCompartor implements Comparator{

@Overridepublic intcompare(Person o1, Person o2) {return o1.getAge()-o2.getAge();

}

}//测试

public static voidmain(String[] args) {

Person[] people= new Person[]{new Person("fsx", 18), new Person("dy", 15)};

System.out.println("排序前:" +StringUtils.arrayToCommaDelimitedString(people));

Arrays.sort(people,new PersonCompartor()); //使用自定义的比较器排序

System.out.println("排序后:" +StringUtils.arrayToCommaDelimitedString(people));

}

结果:

排序前:Person{name='fsx', age=18},Person{name='dy', age=15}

排序后:Person{name='dy', age=15},Person{name='fsx', age=18}

可以看到完全按照我们自己定义的比较器排序了。并且,并且,并且Person是没有实现排序接口的哦,所以**是没有侵入性的**。

Comparable和Comparator区别比较

Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。解耦了~~

Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。

个性化比较:如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法。

Comparable接口是 java.lang包下的 而 Comparator接口才是java.util包下的。(由此课件后者被归类为一种工具)

两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。(有侵入性)

用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。

Comparator接口中的默认方法和静态方法

JDK1.8后,在此接口中Comparator定义了好些个静态方法和默认方法,很多时候我们能够当作工具来使用。

default方法属于实例的,static方法属于类的(当然实例也可使用)

//逆序排序 用于集合的排序~

default Comparatorreversed() {return Collections.reverseOrder(this);

}//Demo

public static voidmain(String[] args) {

Person[] people= new Person[]{new Person("fsx", 18), new Person("dy", 15)};

System.out.println("排序前:" +StringUtils.arrayToCommaDelimitedString(people));

Arrays.sort(people,new PersonCompartor().reversed()); //使用自定义的比较器排序

System.out.println("排序后:" +StringUtils.arrayToCommaDelimitedString(people));

}//Demo结果:这样reversed一下 就逆序了~~~

排序前:Person{name='fsx', age=18},Person{name='dy', age=15}

排序后:Person{name='fsx', age=18},Person{name='dy', age=15}//可以很方便的实现两层排序:比如先按照年龄排序 再按照名字排序等等~~~~

default Comparator thenComparing(Comparator super T>other) {

Objects.requireNonNull(other);return (Comparator & Serializable) (c1, c2) ->{int res =compare(c1, c2);return (res != 0) ?res : other.compare(c1, c2);

};

}default > ComparatorthenComparing(

Function super T, ? extends U>keyExtractor)

{returnthenComparing(comparing(keyExtractor));

}default ComparatorthenComparing(

Function super T, ? extends U>keyExtractor,

Comparator super U>keyComparator)

{returnthenComparing(comparing(keyExtractor, keyComparator));

}default Comparator thenComparingInt(ToIntFunction super T>keyExtractor) {returnthenComparing(comparingInt(keyExtractor));

}default Comparator thenComparingLong(ToLongFunction super T>keyExtractor) {returnthenComparing(comparingLong(keyExtractor));

}default Comparator thenComparingDouble(ToDoubleFunction super T>keyExtractor) {returnthenComparing(comparingDouble(keyExtractor));

}//Demo:

public static voidmain(String[] args) {

Person[] people= new Person[]{new Person("fsx", 18), new Person("dy", 15)};

System.out.println("排序前:" +StringUtils.arrayToCommaDelimitedString(people));

Arrays.sort(people,new PersonCompartor().thenComparing(Person::getName)); //使用自定义的比较器排序

System.out.println("排序后:" +StringUtils.arrayToCommaDelimitedString(people));

}

下面看看静态方法:

public static > ComparatorreverseOrder() {returnCollections.reverseOrder();

}//按照自然排序的一个比较器

public static > ComparatornaturalOrder() {return (Comparator) Comparators.NaturalOrderComparator.INSTANCE;

}//它俩是对比较器进行了包装,对null友好了

public static Comparator nullsFirst(Comparator super T>comparator) {return new Comparators.NullComparator<>(true, comparator);

}public static Comparator nullsLast(Comparator super T>comparator) {return new Comparators.NullComparator<>(false, comparator);

}//Demo

public static voidmain(String[] args) {//放置一个null值

Person[] people = new Person[]{new Person("fsx", 18), null, new Person("dy", 15)};

System.out.println("排序前:" +StringUtils.arrayToCommaDelimitedString(people));

Arrays.sort(people, Comparator.nullsFirst(new PersonCompartor())); //使用自定义的比较器排序

System.out.println("排序后:" +StringUtils.arrayToCommaDelimitedString(people));

}//结果 把null放在了第一位

排序前:Person{name='fsx', age=18},null,Person{name='dy', age=15}

排序后:null,Person{name='dy', age=15},Person{name='fsx', age=18}//它只需要一个函数,所以要求你取出来的这个字段是实现了Comparable接口的,所以你从泛型约束中也能看出来

public static > Comparatorcomparing(

Function super T, ? extends U>keyExtractor)

{

Objects.requireNonNull(keyExtractor);return (Comparator &Serializable)

(c1, c2)->keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));

}//和comparing 方法一不同的是 该方法多了一个参数 keyComparator ,keyComparator 是创建一个自定义的比较器 注意是只比较的是key//比如这样子:Arrays.sort(people, Comparator.comparing(Person::getAge, (a1, a2) -> a2 - a1));//使用自定义的比较器排序

public static Comparatorcomparing(

Function super T, ? extends U>keyExtractor,

Comparator super U>keyComparator)

{

Objects.requireNonNull(keyExtractor);

Objects.requireNonNull(keyComparator);return (Comparator &Serializable)

(c1, c2)->keyComparator.compare(keyExtractor.apply(c1),

keyExtractor.apply(c2));

}//Arrays.sort(people, Comparator.comparingInt(Person::getAge)); 他们不能自定义比较器了

public static Comparator comparingInt(ToIntFunction super T>keyExtractor) {

Objects.requireNonNull(keyExtractor);return (Comparator &Serializable)

(c1, c2)->Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));

}public static Comparator comparingLong(ToLongFunction super T>keyExtractor) {

Objects.requireNonNull(keyExtractor);return (Comparator &Serializable)

(c1, c2)->Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));

}public static Comparator comparingDouble(ToDoubleFunction super T>keyExtractor) {

Objects.requireNonNull(keyExtractor);return (Comparator &Serializable)

(c1, c2)->Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));

}

Spring中的ComparableComparator和Comparators

备注此处的Comparators指的是Spring包下的:org.springframework.util.comparator.Comparators,因为JDK自带的java.util.Comparators它是不提供给外部访问的。

ComparableComparator

//@since 1.2.2 比较器,用于将可比较器适配比较器接口。

public class ComparableComparator> implements Comparator{//实例 单例 这样子的话就可以当作Comparator来使用了

@SuppressWarnings("rawtypes")public static final ComparableComparator INSTANCE = newComparableComparator();

@Overridepublic intcompare(T o1, T o2) {returno1.compareTo(o2);

}

}

这个适配类是Spring1.2.2就出来了,但是下面的工具:Comparators可是Spring5.0才提供

Comparators

它是Spring5.0后提供的一个工具类,里面主要是提供了一些静态方法,来提供外部比较器。

//@since 5.0 注意使用它和直接使用Comparator的区别是,它要求你比较的对象都实现了Comparable的 否则都是不适用的

public abstract classComparators {//自然排序~~~~//Arrays.sort(people, Comparators.comparable()); 比如你这么用,是要求peple里面元素实现了Comparable接口的 否则报错

@SuppressWarnings("unchecked")public static Comparatorcomparable() {returnComparableComparator.INSTANCE;

}//null放在最后

@SuppressWarnings("unchecked")public static ComparatornullsLow() {returnNullSafeComparator.NULLS_LOW;

}/// null放最后 并且我们还可以提供一个自定义的比较器

public static Comparator nullsLow(Comparatorcomparator) {return new NullSafeComparator<>(comparator, true);

}

@SuppressWarnings("unchecked")public static ComparatornullsHigh() {returnNullSafeComparator.NULLS_HIGH;

}public static Comparator nullsHigh(Comparatorcomparator) {return new NullSafeComparator<>(comparator, false);

}

}

OrderComparator

使用OrderComparator来比较2个对象的排序顺序。注意它用于Spring用来比较实现了Ordered接口的对象。

注意它@since 07.04.2003出现得非常早,所以这个类并不支持@Order注解的排序~~~

但是,PriorityOrdered接口它也是支持的,虽然它Spring2.5才出现。

另外,它是一个Comparator,所以它可以作为自定义比较器放在数组、集合里排序。形如;

public class OrderComparator implements Comparator{

...public static void sort(List>list) {if (list.size() > 1) {

list.sort(INSTANCE);

}

}public static voidsort(Object[] array) {if (array.length > 1) {

Arrays.sort(array, INSTANCE);

}

}public static voidsortIfNecessary(Object value) {if (value instanceofObject[]) {

sort((Object[]) value);

}else if (value instanceofList) {

sort((List>) value);

}

}

}

AnnotationAwareOrderComparator

AnnotationAwareOrderComparator继承自OrderComparator

其可以同时处理对象实现Ordered接口或@Order注解。

显然它增强了排序能力,不仅支持Ordered接口,还支持到了@Order注解。

@Order注解@since 2.0,AnnotationAwareOrderComparator它@since 2.0.1,几乎同时出现的

它提供了两个静态方法,使用非常广泛,方便我们对数组、即可记性排序:

public class AnnotationAwareOrderComparator extendsOrderComparator {/*** 用来检查实现Ordered接口、@Order和@Priority注解*/

protectedInteger findOrder(Object obj) {//检查常规的Ordered接口,通过子类重写的getOrder方法返回顺序值

Integer order = super.findOrder(obj);if (order != null) {returnorder;

}//检查实现@Order和@Priority注解

if (obj instanceofClass) {//在类上检查@Order和@Priority注解,并找出顺序值

return OrderUtils.getOrder((Class>) obj);

}else if (obj instanceofMethod) {//在方法上检查@Order注解,并找出顺序值

Order ann = AnnotationUtils.findAnnotation((Method) obj, Order.class);if (ann != null) {returnann.value();

}

}else if (obj instanceofAnnotatedElement) {//在注解中找@Order注解,并找出顺序值

Order ann = AnnotationUtils.getAnnotation((AnnotatedElement) obj, Order.class);if (ann != null) {returnann.value();

}

}else if (obj != null) {

order=OrderUtils.getOrder(obj.getClass());if (order == null && obj instanceofDecoratingProxy) {

order=OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());

}

}returnorder;

}//==================================================================//注意此处和上面的区别,它用的是自己的instance

public static void sort(List>list) {if (list.size() > 1) {

list.sort(INSTANCE);

}

}*/

public static voidsort(Object[] array) {if (array.length > 1) {

Arrays.sort(array, INSTANCE);

}

}public static voidsortIfNecessary(Object value) {if (value instanceofObject[]) {

sort((Object[]) value);

}else if (value instanceofList) {

sort((List>) value);

}

}

}

OrderUtils

最后介绍这个工具类,它是Spring4.1后提出的。它支持注解@Order和javax.annotation.Priority也是被支持的,因此它的getOrder()方法就是获取order值了。

需要注意的是:先找@Order,若没有再去找@Priority,都没标注就返回默认值

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值