“順序“在任何一個領域里都是非常重要的一個概念,程序也不例外。不同的執行順序,能對你的執行結果產生直接影響。
既然涉及到順序,那就要求排序。所以本文討論的就是排序中使用到的比較器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> { // 這里入參也是T 所以是自己和自己比較的 // 規則:this和t比較。 返回0表示兩個對象相等 // 返回正數: this > o // 返回負數: this < o public int compareTo(T o); }
比如如下例子:
public static void main(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該接口增加了很多默認方法,后面也會講解 @FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(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 class Person { public String name; public Integer age; } // person類的Compartor比較器 泛型類型為Person // 按照 public class PersonCompartor implements Comparator<Person> { @Override public int compare(Person o1, Person o2) { return o1.getAge()-o2.getAge(); } } // 測試 public static void main(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 Comparator<T> reversed() { return Collections.reverseOrder(this); } // Demo public static void main(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<T> thenComparing(Comparator<? super T> other) { Objects.requireNonNull(other); return (Comparator<T> & Serializable) (c1, c2) -> { int res = compare(c1, c2); return (res != 0) ? res : other.compare(c1, c2); }; } default <U extends Comparable<? super U>> Comparator<T> thenComparing( Function<? super T, ? extends U> keyExtractor) { return thenComparing(comparing(keyExtractor)); } default <U> Comparator<T> thenComparing( Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) { return thenComparing(comparing(keyExtractor, keyComparator)); } default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) { return thenComparing(comparingInt(keyExtractor)); } default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) { return thenComparing(comparingLong(keyExtractor)); } default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) { return thenComparing(comparingDouble(keyExtractor)); } // Demo: public static void main(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 <T extends Comparable<? super T>> Comparator<T> reverseOrder() { return Collections.reverseOrder(); } // 按照自然排序的一個比較器 public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() { return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE; } // 它倆是對比較器進行了包裝,對null友好了 public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) { return new Comparators.NullComparator<>(true, comparator); } public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) { return new Comparators.NullComparator<>(false, comparator); } // Demo public static void main(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 <T, U extends Comparable<? super U>> Comparator<T> comparing( Function<? super T, ? extends U> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & 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 <T, U> Comparator<T> comparing( Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) { Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyComparator); return (Comparator<T> & Serializable) (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2)); } // Arrays.sort(people, Comparator.comparingInt(Person::getAge)); 他們不能自定義比較器了 public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); } public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); } public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & 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<T extends Comparable<T>> implements Comparator<T> { // 實例 單例 這樣子的話就可以當作Comparator來使用了 @SuppressWarnings("rawtypes") public static final ComparableComparator INSTANCE = new ComparableComparator(); @Override public int compare(T o1, T o2) { return o1.compareTo(o2); } }
這個適配類是Spring1.2.2就出來了,但是下面的工具:Comparators
可是Spring5.0才提供
Comparators
它是Spring5.0后提供的一個工具類,里面主要是提供了一些靜態方法,來提供外部比較器。
// @since 5.0 注意使用它和直接使用Comparator的區別是,它要求你比較的對象都實現了Comparable的 否則都是不適用的 public abstract class Comparators { // 自然排序~~~~ // Arrays.sort(people, Comparators.comparable()); 比如你這么用,是要求peple里面元素實現了Comparable接口的 否則報錯 @SuppressWarnings("unchecked") public static <T> Comparator<T> comparable() { return ComparableComparator.INSTANCE; } // null放在最后 @SuppressWarnings("unchecked") public static <T> Comparator<T> nullsLow() { return NullSafeComparator.NULLS_LOW; } /// null放最后 並且我們還可以提供一個自定義的比較器 public static <T> Comparator<T> nullsLow(Comparator<T> comparator) { return new NullSafeComparator<>(comparator, true); } @SuppressWarnings("unchecked") public static <T> Comparator<T> nullsHigh() { return NullSafeComparator.NULLS_HIGH; } public static <T> Comparator<T> nullsHigh(Comparator<T> comparator) { return new NullSafeComparator<>(comparator, false); } }
OrderComparator
使用OrderComparator
來比較2個對象的排序順序。注意它用於Spring用來比較實現了Ordered
接口的對象。
注意它@since 07.04.2003
出現得非常早,所以這個類並不支持@Order
注解的排序~~~
但是,PriorityOrdered
接口它也是支持的,雖然它Spring2.5才出現。
另外,它是一個Comparator
,所以它可以作為自定義比較器放在數組、集合里排序。形如;
public class OrderComparator implements Comparator<Object> { ... public static void sort(List<?> list) { if (list.size() > 1) { list.sort(INSTANCE); } } public static void sort(Object[] array) { if (array.length > 1) { Arrays.sort(array, INSTANCE); } } public static void sortIfNecessary(Object value) { if (value instanceof Object[]) { sort((Object[]) value); } else if (value instanceof List) { sort((List<?>) value); } } }
AnnotationAwareOrderComparator
AnnotationAwareOrderComparator繼承自OrderComparator
其可以同時處理對象實現Ordered接口或@Order注解。
顯然它增強了排序能力,不僅支持Ordered接口,還支持到了@Order注解。
@Order注解@since 2.0,AnnotationAwareOrderComparator它@since 2.0.1,幾乎同時出現的
它提供了兩個靜態方法,使用非常廣泛,方便我們對數組、即可記性排序:
public class AnnotationAwareOrderComparator extends OrderComparator { /** * 用來檢查實現Ordered接口、@Order和@Priority注解 */ protected Integer findOrder(Object obj) { // 檢查常規的Ordered接口,通過子類重寫的getOrder方法返回順序值 Integer order = super.findOrder(obj); if (order != null) { return order; } // 檢查實現@Order和@Priority注解 if (obj instanceof Class) { // 在類上檢查@Order和@Priority注解,並找出順序值 return OrderUtils.getOrder((Class<?>) obj); } else if (obj instanceof Method) { // 在方法上檢查@Order注解,並找出順序值 Order ann = AnnotationUtils.findAnnotation((Method) obj, Order.class); if (ann != null) { return ann.value(); } } else if (obj instanceof AnnotatedElement) { // 在注解中找@Order注解,並找出順序值 Order ann = AnnotationUtils.getAnnotation((AnnotatedElement) obj, Order.class); if (ann != null) { return ann.value(); } } else if (obj != null) { order = OrderUtils.getOrder(obj.getClass()); if (order == null && obj instanceof DecoratingProxy) { order = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass()); } } return order; } // ================================================================== // 注意此處和上面的區別,它用的是自己的instance public static void sort(List<?> list) { if (list.size() > 1) { list.sort(INSTANCE); } } */ public static void sort(Object[] array) { if (array.length > 1) { Arrays.sort(array, INSTANCE); } } public static void sortIfNecessary(Object value) { if (value instanceof Object[]) { sort((Object[]) value); } else if (value instanceof List) { sort((List<?>) value); } } }
OrderUtils
最后介紹這個工具類,它是Spring4.1后提出的。它支持注解@Order和javax.annotation.Priority也是被支持的,因此它的getOrder()方法就是獲取order值了。
需要注意的是:先找@Order,若沒有再去找@Priority,都沒標注就返回默認值