? ? 對(duì)于集合來說盛末,排序是一個(gè)很常見的操作抖锥,Java已經(jīng)提供了一系列排序的方法登舞,如Collections中的靜態(tài)方法public static void sort(List list, Comparator c); List接口提供的default? void sort(Comparator c); Java Stream提供的sorted(Comparator c) 菲驴,只需要傳入滿足排序規(guī)則的Comparator,就可以輕松的完成排序错英;然而入撒,遺憾的是,作為排序操作之中最重要最關(guān)鍵的排序規(guī)則構(gòu)造椭岩,即Comparator的構(gòu)造茅逮,原生的Java庫并沒有提供相對(duì)簡單易懂的構(gòu)造工具和方法。
? ? 一些第三方的工具庫已經(jīng)對(duì)此不足判哥,做了相應(yīng)的補(bǔ)充献雅,其中比較具有知名度,并且簡單易用的有Guava的Ordering姨伟、Apache工具類提供的比較器構(gòu)造方法惩琉。本篇文章也主要是圍繞這兩者提供的Comparator構(gòu)造方法進(jìn)行介紹和比較進(jìn)行展開,詳細(xì)介紹兩種方法的優(yōu)點(diǎn)夺荒。
? ? 我們平時(shí)需要用到的復(fù)雜排序規(guī)則主要會(huì)有瞒渠,倒序、自然數(shù)大小排序技扼,字典大小排序伍玖、多規(guī)則排序鏈(第一排序、第二排序......)等剿吻。下面比較Java原生的Comparator構(gòu)造方法窍箍、Guava的Ordering、Apache工具類提供的構(gòu)造Comparator方法丽旅,說明是Guava的Ordering椰棘、Apache工具類怎么簡單、靈活解決滿足這些排序規(guī)則的榄笙。
一邪狞、Apache工具類ComparableComparator、ComparatorUtils茅撞、ComparatorChain
ComparableComparator.getInstance ();
ComparatorUtils.naturalComparator();
均能提供一個(gè)自然排序的Comparator(數(shù)字從小到大排序帆卓、字典排序),這個(gè)是復(fù)雜Comparator構(gòu)造的基礎(chǔ)米丘。
個(gè)人認(rèn)為Guava和Apache構(gòu)造Comparator都有用到裝飾者設(shè)計(jì)模式的思想剑令,先構(gòu)造出最基本的自然排序Comparator,再一層一層裝飾上其他的排序規(guī)則拄查。
Apache里面構(gòu)造復(fù)雜比較規(guī)則的方法主要在ComparatorUtils和BeanComparator吁津。
BeanComparator構(gòu)造的比較器可以用類對(duì)象里面的property字段按照傳入的comparator比較器規(guī)則進(jìn)行排序。
BeanComparator(String property, Comparator comparator)
ComparatorUtils則提供一系列裝飾排序規(guī)則的方法;
多規(guī)則排序鏈(第一排序堕扶、第二排序......):
public static Comparator chainedComparator(Comparator[] comparators)腺毫;
倒序排序
public static Comparator reversedComparator(Comparator comparator)癣疟;
集合中有Null值,Null放置在排序序列的前面潮酒;
public static Comparator nullHighComparator(Comparator comparator);
相反的邪蛔,集合中有Null值急黎,Null放置在排序序列的后面;
public static Comparator nullLowComparator(Comparator comparator)侧到;
對(duì)比較對(duì)象做處理勃教,Transformer返回值進(jìn)行排序,類似于BeanComparator(String property, Comparator comparator)匠抗,添加了復(fù)雜性故源,但更處理比較對(duì)象的自由度也更高。
public static Comparator transformedComparator(Comparator comparator, Transformer transformer)汞贸;
其他不屬于構(gòu)造比較器的方法绳军,根據(jù)比較規(guī)則獲取最小\最大對(duì)象。
public static Object min(Object o1, Object o2, Comparator comparator);
public static Object max(Object o1, Object o2, Comparator comparator);
二矢腻、Guava的Ordering
? ? Ordering是Guava流暢風(fēng)格比較器[Comparator]的實(shí)現(xiàn)门驾,它可以用來為構(gòu)建復(fù)雜的比較器,以完成集合排序的功能多柑。從實(shí)現(xiàn)上說奶是,Ordering extends Comparator,提供了鏈?zhǔn)秸{(diào)用方法竣灌,來定制和增強(qiáng)現(xiàn)有的比較器聂沙。其中鏈?zhǔn)秸{(diào)用構(gòu)造Ordering ( extends Comparator)是Ordering相對(duì)于Apache工具類構(gòu)造Comparator來說最大的特色,提高了構(gòu)造的簡潔和易用性初嘹,個(gè)人喜歡這種風(fēng)格去構(gòu)造Comparator及汉。
類似的,Ordering也提供了基礎(chǔ)的自然排序Ordering
public static Ordering natural();
添加了按對(duì)象的字符串形式做字典排序的基礎(chǔ)Ordering
public static Ordering usingToString();
更提供了將普通Comparator轉(zhuǎn)化成Ordering的方法削樊,這也提供了Java原生Comparator構(gòu)造豁生、Apache工具類構(gòu)造和Ordering構(gòu)造混用的可能,能夠?qū)σ延械腃omparator進(jìn)行加強(qiáng)漫贞、裝飾甸箱。
public static Ordering from(Comparator comparator);
下面是Ordring提供構(gòu)造復(fù)雜Ordering的方法;
多規(guī)則排序鏈(第一排序迅脐、第二排序......);
public Ordering compound(Comparator secondaryComparator);
public static Ordering compound(Iterable?comparators);
按照給定的順序進(jìn)行排序芍殖。
public static Ordering explicit(List valuesInOrder);
倒序排序
public Ordering reverse();
null值在前面排序
public Ordering nullsFirst();
null值在后面排序
publicOrdering nullsLast();
對(duì)比較對(duì)象做處理,按Function 返回值進(jìn)行排序谴蔑;
public Ordering onResultOf(Function function)豌骏;
其他不屬于構(gòu)造比較器的方法:
根據(jù)比較規(guī)則獲取最小\最大對(duì)象龟梦。
public?E min(Iterable iterable)
public?E max(Iterable iterable)
根據(jù)比較規(guī)則獲取最小\最大k個(gè)對(duì)象。
public List greatestOf(Iterable iterable,int k);
public List leastOf(Iterable iterable,int k);
? ? 前面提到窃躲,Ordering也使用到了裝飾者設(shè)計(jì)思想计贰,可以看到Ordering構(gòu)造方法都不用傳入被裝飾的ordering,這是因?yàn)镺rdering鏈?zhǔn)秸{(diào)用的好處蒂窒,直接在方法中用this,就能夠獲取到被裝飾的對(duì)象躁倒。
鏈?zhǔn)秸{(diào)用需要是倒著讀的,從后往前讀如下洒琢。排序器首先調(diào)用apply方法獲取sortedBy值秧秉,并把sortedBy為null的元素都放到最前面,然后把剩下的元素按sortedBy進(jìn)行自然排序衰抑。
Ordering ordering = Ordering.natural().nullsFirst().onResultOf(function)象迎;
類似的用Apache工具類實(shí)現(xiàn)則為
Comparator.nullHighComparator((Comparator.transformedComparator(ComparatorUtils.naturalComparator(),funtion));
三、Java原生的Comparator構(gòu)造方法
? ? 雖然Java原生的Comparator構(gòu)造方法不如前兩者簡單易用呛踊,但其實(shí)Comparator類中也提供了一些比較簡單的構(gòu)造Comparator的方法砾淌,而不需要在public int compare(To1,To2)方法里面用一長串多層If嵌套的代碼來編寫排序規(guī)則。
Comparator很類似于Ordering恋技,Comparator類也提供了基礎(chǔ)的自然排序拇舀。
public static?Comparator naturalOrder();
public static?Comparator reverseOrder()蜻底; //自然排序倒序
null值在前面排序
public static Comparator nullsFirst(Comparator comparator)骄崩;
null值在后面排序
public static Comparator nullsLast(Comparator comparator);
對(duì)比較對(duì)象做處理薄辅,按Function 返回值進(jìn)行排序要拂;
public static Comparator comparing(Function keyExtractor,Comparator keyComparator);
多規(guī)則排序(第一排序站楚、第二排序......);
Comparator thenComparing(Comparator other)脱惰;
? ? 可以看到Ordering和原生的Java Comparator構(gòu)造方法有很多相似之處,相比之下窿春,Comparator只不過是沒Ordering功能那么強(qiáng)大拉一,但也不算很糟糕。
下面通過一個(gè)例子來展示上面三種構(gòu)造方法的區(qū)別旧乞。
? ? 一個(gè)User類蔚润,里面有id,firstName尺栖,lastName嫡纠,age字段,現(xiàn)在按照優(yōu)先級(jí)為age升序、firstName升序除盏、lastName倒序進(jìn)行排序叉橱,代碼如下。