起因:在寫JDK Collections工具類的時(shí)候?qū)懙琅判蚺钠ぃ笤创a比較的長(zhǎng)签餐,就分開(kāi)來(lái)做一篇博客斗幼,之前也有在stream流中用到排序,今天來(lái)搞明白它到底是怎么一回事宗兼,還有就是Comparator與Comparable傻傻分不清楚怎么辦躏鱼?帶著問(wèn)題來(lái)學(xué)習(xí)比較器與可比較的接口的區(qū)別吧。
1.Comparator與Comparable
從字面意思上來(lái)說(shuō)呢殷绍,
Comparator是比較器染苛,是作為一個(gè)工具類形式的存在,但是它又是一個(gè)接口(函數(shù)式),所以我認(rèn)為它是方便人們用來(lái)進(jìn)行比較的工具類茶行。因?yàn)楹脤?shí)現(xiàn)嘛??躯概。
Comparable是‘有比較能力的’,是用來(lái)讓別的類進(jìn)行實(shí)現(xiàn)的畔师,其內(nèi)部只有一個(gè)接口娶靡,compareTo(T o),例如String類的compareTo(T o)方法??看锉∽硕В可能我的想法太幼稚了。哈哈
JDK8 中 排序可以使用stream中的sorted
2.Comparator接口
2.1 Comparator的主要方法
//比較的方法
int compare(T o1, T o2);
comparing
thenComparing
2.2使用到Comparator接口的地方
Arrays.sort(T[],Comparator<? super T> c);
Collections.sort(List<T> list,Comparator<? super T> c);
//Stream類中
2.3 comparing與 thenComparing方法的使用
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));
}
其返回值是 (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); 一個(gè)lambda表達(dá)式伯铣,也就是一個(gè)Compator 呻此。
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);
};
}
2.4實(shí)際運(yùn)用與填坑
default 是一個(gè)jdk8的新特性 讓后來(lái)在接口中新增的代碼 之前實(shí)現(xiàn)過(guò)該接口的類不用重寫。
他們的參數(shù)相同懂傀,但是返回值卻不同趾诗。
比如蜡感,我要根據(jù)某個(gè)類的某個(gè)屬性進(jìn)行排序:
personList.stream().sorted(Comparator.comparing(( p) -> -
p.getCars().size()).thenComparing(Person::getId)).collect(Collectors.toList());
這樣是會(huì)報(bào)錯(cuò)的蹬蚁,代碼在p.getCars.size() 處報(bào)錯(cuò),cannot resolve method "getCars()"郑兴。這里一定有人會(huì)糾結(jié)為什么我寫的也是函數(shù)式編程犀斋,按道理沒(méi)問(wèn)題呀!但是編輯器就是不認(rèn)識(shí)p.getCars()情连。
正確的寫法應(yīng)該是下面這樣的:
personList.stream().sorted(Comparator.comparing(( Person p) -> -
p.getCars().size()).thenComparing(Person::getId)).collect(Collectors.toList());
所以使用thenComparing方法會(huì)比較方便一些叽粹,不用再寫類型了。
以下是Collections中sort方法的源碼
//默認(rèn)排序
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
//自定義排序
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
int nRemaining = hi - lo;
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted
// If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi);
binarySort(a, lo, hi, lo + initRunLen);
return;
}
/**
* March over the array once, left to right, finding natural runs,
* extending short natural runs to minRun elements, and merging runs
* to maintain stack invariant.
*/
ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
int minRun = minRunLength(nRemaining);
do {
// Identify next run
int runLen = countRunAndMakeAscending(a, lo, hi);
// If run is short, extend to min(minRun, nRemaining)
if (runLen < minRun) {
int force = nRemaining <= minRun ? nRemaining : minRun;
binarySort(a, lo, lo + force, lo + runLen);
runLen = force;
}
// Push run onto pending-run stack, and maybe merge
ts.pushRun(lo, runLen);
ts.mergeCollapse();
// Advance to find next run
lo += runLen;
nRemaining -= runLen;
} while (nRemaining != 0);
// Merge all remaining runs to complete sort
assert lo == hi;
ts.mergeForceCollapse();
assert ts.stackSize == 1;
}
}
不要以為每天把功能完成了就行了却舀,這種思想是要不得的虫几,互勉~!