關(guān)于排序
眾所周知,如果需要在
Java
中使用排序方法,那么就需要實(shí)現(xiàn)
Comparable
接口。
?
public interface java.lang.Comparable {
??????????????public int compareTo(Object o);
???? }
|
|
????Comparable
接口很簡單,因?yàn)樗挥幸粋€(gè)方法;然而如果你需要根據(jù)多
個(gè)屬性對(duì)對(duì)象進(jìn)行排序,那么實(shí)現(xiàn)
compareTo
方法就會(huì)變得很復(fù)雜。
??????
下邊就是一個(gè)摘自
Jakarta Commons cookbook
的例子:
package com.discursive.jccook.collections.compare;
import java.util.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.collections.comparators.ReverseComparator;
public class BookComparator implements Comparator {
???
public int compare(Object o1, Object o2) {
????????
int comparison = -1;
???????
if( o1 instanceof Book && o2 instanceof Book ) {
??????????? Book b1 = (Book) o1;
??????????? Book b2 = (Book) o2;
???????????? String b1Name = b1.getName( );
???????????? String b2Name = b2.getName( );
???????????? String b1Author = b1.getAuthor( );
???????????? String b2Author = b2.getAuthor( );
??????????? if( StringUtils.isNotEmpty( b1Name ) &&
?????????????? StringUtils.isNotEmpty( b2Name ) ) {
???????
?????????comparison = b1Name.compareTo( b2Name );
??????????? }
??????????? if( comparison == 0 &&
??????????????? StringUtils.isNotEmpty( b1Author ) &&
??????????????? StringUtils.isNotEmpty( b2Author ) ) {
??????????????? comparison = b1Author.compareTo( b2Author );
??????????? }??
??????? }
??????? return comparison;
??? }
}
???該事例是對(duì)一個(gè)稱為
book
的
bean
進(jìn)行排序,將會(huì)根據(jù)
name
和
author
兩個(gè)屬性進(jìn)行排序。當(dāng)我們使用的時(shí)候,就可以類似于以下的形式。
?????Arrary.sort(books,BookComparator)
或者
collections.sort
(books,BookComparator).
當(dāng)中的兩個(gè)參數(shù)是要排序的數(shù)組或者
list
以及使
用的
Comparator
。下邊主要說的就是怎樣構(gòu)造
Comparator
。
本文的是展示怎樣使用
commons
的組件,來完成
Comparator
的構(gòu)造。
對(duì)單一
bean
的單個(gè)屬性排序
??????
現(xiàn)在如果我們只是想對(duì)
bean
中的一個(gè)屬性進(jìn)行排序的話。那么只需要構(gòu)造
出一個(gè)
BeanComparator
的實(shí)例就可以了
.
形式如下:
?
private BeanComparator comparator = new BeanComparator("name");
??????
這樣子我們就構(gòu)造出了一個(gè)根據(jù)
”name”
屬性來對(duì)集合中的
bean
進(jìn)行排
序的比較器。當(dāng)集合中的
bean
有
name
這個(gè)屬性的時(shí)候,那么排序時(shí)就會(huì)依照
這個(gè)排序器來調(diào)整集合中
bean
的順序。
????BeanComparator
是
BeanUtils API
中的一個(gè)類,使用它可以很簡單地根
據(jù)
bean
的屬性對(duì)
Bean
類進(jìn)行排序。
??????
需要說明的是這個(gè)比較器只是對(duì)符合
javabean
規(guī)范的類進(jìn)行比較,如果類
中沒有這個(gè)屬性或者屬性沒有
get
和
set
方法,那么在比較的時(shí)候就會(huì)拋出
ClassCastException
。
裝飾比較器
??????
上邊生成的比較器是帶有一些默認(rèn)的排序規(guī)則的,比如按著自然順序排列,
當(dāng)遇到字符串的值是“”的時(shí)候就排列在前端。下邊我將說明怎么改變這種默認(rèn)
的規(guī)則。
??????
為了完成這個(gè)任務(wù),我們就需要使用
commons.collections.comparators
提供的幾個(gè)裝飾類,ReverseComparator,NullComparator,
FixedOrderComparator或者ComparatorUtils這個(gè)實(shí)用類。
???
下邊分別說明反序排列,允許空值排列和自定義順序排列的實(shí)現(xiàn)方法。
???
當(dāng)我們想對(duì)讓一個(gè)比較器按著反序進(jìn)行排列的時(shí)候,可以使用如下的形
式:
??????comparator = new ReverseComparator(comparator);
??????
需要說明的是:這個(gè)功能的實(shí)現(xiàn)可以在排完序后對(duì)要排序的
array
或者
list
調(diào)用其
reverse
()方法即可。但是這種做法并不適合下邊談到的對(duì)
bean
的多字段排序時(shí),而只對(duì)某一個(gè)字段逆序的情況。?
??? 當(dāng)對(duì)一個(gè)比較器進(jìn)行特定順序排列時(shí)需要用到FixedOrderComparator 。
這個(gè)類用于定義一個(gè)特殊的順序,對(duì)一組對(duì)象按照這樣的自定義順序進(jìn)行排序。
具體的事例如下:
String[] severityOrder = { "Critical", "Minor", "Enhancement" };
Comparator severityComparator = new FixedOrderComparator
(severityOrder);
Comparator comparator=new BeanComparator("title",severityComparator)
;
如上的程序便可以對(duì)
bean
的
title
屬性按著數(shù)組中特定
的順序進(jìn)行排序!
最后需要說明的是,以上談到的幾個(gè)裝飾在
ComparatorUtils
這個(gè)實(shí)用類中也提供了支持。
具體使用如下:
按著
bean
的屬性為
null
時(shí)進(jìn)行排序,可以選擇屬性為
null
時(shí)排在前邊還是后邊!
ComparatorUtils.nullLowComparator(comparator);?
或者
ComparatorUtils.nullHighComparator(comparator);
當(dāng)對(duì)一個(gè)排序器逆序時(shí):
ComparatorUtils.reversedComparator(mycmp); //
逆序
多個(gè)屬性的排序
當(dāng)我們想對(duì)
bean
的多個(gè)屬性進(jìn)行排序的時(shí)候,需要用到
commons.collections. ComparatorChain
。這個(gè)類
定義一組Comparator鏈,鏈中的Comparator對(duì)象會(huì)被依次執(zhí)行。我們可以通過該類的 addComparator()
方法進(jìn)行將當(dāng)個(gè)的
comparator
對(duì)象加入到
comparator
鏈中,當(dāng)使用的時(shí)候就可以和使用單個(gè)
comparator
一樣。因?yàn)?/span>
comparatorChain
也繼承了
comparator
的借口。當(dāng)我們添加單個(gè)的
comparator
的時(shí)候,就可以利用上邊談到的對(duì)
comparator
進(jìn)行裝飾。
ComparatorChain comparatorChain = new ComparatorChain( );
comparatorChain.addComparator( new BeanComparator( "name" ) );
comparatorChain.addComparator( new BeanComparator( "author" ) );
comparaterChain.addComparator( new ReverseComparator?????????????????????????????
(new BeanComparator("author") );
???
?
具體使用的時(shí)候如下:
????Arrays.sort( books, comparatorChain );
?
這個(gè)樣子就可以將這個(gè)
comparator
傳給
sort
()方法。當(dāng)談到對(duì)
bean
的多字段排序,而只對(duì)某一個(gè)字段逆序的情況時(shí),可以參考如下的實(shí)現(xiàn)。
????
?ComparatorChain comparatorChain = new ComparatorChain( );
???? comparatorChain.addComparator( new BeanComparator( "name" ) );
?????
?
這樣子就可以實(shí)現(xiàn)了對(duì)
bean
的
name
按著正序排列而對(duì)
author
屬性按著逆序排列。
對(duì)組合
bean
進(jìn)行排序
????
?
當(dāng)一個(gè)
bean
的某個(gè)屬性是另外一個(gè)
java bean
的時(shí)候,而我們有想按著那個(gè)被組合進(jìn)來
bean
的某個(gè)屬性進(jìn)行排序的時(shí)候,我們只需要很簡單的將
BeanComparator
的參數(shù)設(shè)定成
bean.property
的形式,比如想對(duì)按著
book
的
author
中的
title
屬性進(jìn)行排序的時(shí)候就可以參考以下的形式:
new BeanComparator
("author.title",severityComparator))
Comparable
接口的實(shí)現(xiàn)
????
?
最后如果想對(duì)
author
類實(shí)現(xiàn)
Comparable
接口可以參考如下的實(shí)現(xiàn):
public class Book implements Comparable {
public int compareTo(Object arg0) {
// comparators setup
String[] severityOrder = { "Critical", "Major", "Minor", "Enhancement" };
//
用于定義一個(gè)特殊的順序,對(duì)一組對(duì)象按照這樣的自定義順序進(jìn)行排序;
Comparator severityComparator = new FixedOrderComparator(severityOrder);
ComparatorChain compChain = new ComparatorChain();
?????? //
通過為屬性指定一個(gè)已經(jīng)存在的
Comparator
,而非采用默認(rèn)的自然順序
compChain.addComparator(new BeanComparator("author.
title", severityComparator));
???
?compChain.addComparator(new NullComparator
(new BeanComparator("name"), true));
compChain .addComparator(new ReverseComparator
(new BeanComparator("id")));
???
?return compChain.compare(this, arg0);
??? }
}
??
另外一個(gè)實(shí)現(xiàn)思路是:利用
commons.lang.compareBulder
實(shí)現(xiàn)。但是卻失去了以上的裝飾功能!
?
??
最后需要說明的是,由于我在工作中最近用到這些排序,所以整理了一下,希望對(duì)您有用。同時(shí)參考了很多網(wǎng)上的資料,謝!
??
事例代碼我放到了:
commons2006@126.com
,
密碼是
commons2006
?