随笔-60  评论-138  文章-1  trackbacks-0

关于排序

众所周知,如果需要在 Java 中使用排序方法,那么就需要实现

Comparable
接口。
 

public interface java.lang.Comparable {

              public int compareTo(Object o);

     }

 

 

    Comparable 接口很简单,因为它只有一个方法;然而如果你需要根据多

个属性对对象进行排序,那么实现
compareTo 方法就会变得很复杂。

      
下边就是一个摘自 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;


   
}


}


   该事例是对一个称为
book bean 进行排序,将会根据 name author

两个属性进行排序。当我们使用的时候,就可以类似于以下的形式。


     Arrary.sort(books,BookComparator)
或者 collections.sort

(books,BookComparator).
当中的两个参数是要排序的数组或者 list 以及使

用的
Comparator 。下边主要说的就是怎样构造 Comparator


本文的是展示怎样使用
commons 的组件,来完成 Comparator 的构造。


对单一
bean 的单个属性排序


      
现在如果我们只是想对 bean 中的一个属性进行排序的话。那么只需要构造

出一个
BeanComparator 的实例就可以了 .


形式如下:
 

private BeanComparator comparator = new BeanComparator("name");


      
这样子我们就构造出了一个根据 ”name” 属性来对集合中的 bean 进行排

序的比较器。当集合中的
bean name 这个属性的时候,那么排序时就会依照

这个排序器来调整集合中
bean 的顺序。


    BeanComparator
BeanUtils API 中的一个类,使用它可以很简单地根

bean 的属性对 Bean 类进行排序。


      
需要说明的是这个比较器只是对符合 javabean 规范的类进行比较,如果类

中没有这个属性或者属性没有
get set 方法,那么在比较的时候就会抛出

ClassCastException


装饰比较器


      
上边生成的比较器是带有一些默认的排序规则的,比如按着自然顺序排列,

当遇到字符串的值是“”的时候就排列在前端。下边我将说明怎么改变这种默认

的规则。


      
为了完成这个任务,我们就需要使用 commons.collections.comparators

提供的几个装饰类,ReverseComparatorNullComparator

FixedOrderComparator
或者ComparatorUtils这个实用类。



   
下边分别说明反序排列,允许空值排列和自定义顺序排列的实现方法。


   
当我们想对让一个比较器按着反序进行排列的时候,可以使用如下的形

式:


      comparator = new ReverseComparator(comparator);


      
需要说明的是:这个功能的实现可以在排完序后对要排序的 array 或者

list
调用其 reverse ()方法即可。但是这种做法并不适合下边谈到的对

bean
的多字段排序时,而只对某一个字段逆序的情况。 

     当对一个比较器进行特定顺序排列时需要用到FixedOrderComparator

这个类用于定义一个特殊的顺序,对一组对象按照这样的自定义顺序进行排序。

具体的事例如下:

String[] severityOrder = { "Critical", "Minor", "Enhancement" };

Comparator severityComparator = new FixedOrderComparator    (severityOrder);

Comparator comparator=new BeanComparator("title",severityComparator)

如上的程序便可以对 bean title 属性按着数组中特定

的顺序进行排序!

最后需要说明的是,以上谈到的几个装饰在 ComparatorUtils 这个实用类中也提供了支持。

具体使用如下:

按着 bean 的属性为 null 时进行排序,可以选择属性为 null 时排在前边还是后边!

ComparatorUtils.nullLowComparator(comparator);  或者 ComparatorUtils.nullHighComparator(comparator);

当对一个排序器逆序时:

ComparatorUtils.reversedComparator(mycmp); // 逆序

 

多个属性的排序

当我们想对 bean 的多个属性进行排序的时候,需要用到 commons.collections. ComparatorChain 。这个类 定义一组Comparator链,链中的Comparator对象会被依次执行。我们可以通过该类的 addComparator() 方法进行将当个的 comparator 对象加入到 comparator 链中,当使用的时候就可以和使用单个 comparator 一样。因为 comparatorChain 也继承了 comparator 的借口。当我们添加单个的 comparator 的时候,就可以利用上边谈到的对 comparator 进行装饰。

ComparatorChain comparatorChain = new ComparatorChain( );

comparatorChain.addComparator( new BeanComparator( "name" ) );

comparatorChain.addComparator( new BeanComparator( "author" ) );

comparaterChain.addComparator( new ReverseComparator                                                        (new BeanComparator("author") );

      具体使用的时候如下:

    Arrays.sort( books, comparatorChain );

  这个样子就可以将这个 comparator 传给 sort ()方法。当谈到对 bean 的多字段排序,而只对某一个字段逆序的情况时,可以参考如下的实现。

      ComparatorChain comparatorChain = new ComparatorChain( );

     comparatorChain.addComparator( new BeanComparator( "name" ) );

        这样子就可以实现了对 bean name 按着正序排列而对 author 属性按着逆序排列。

对组合 bean 进行排序

       当一个 bean 的某个属性是另外一个 java bean 的时候,而我们有想按着那个被组合进来 bean 的某个属性进行排序的时候,我们只需要很简单的将 BeanComparator 的参数设定成 bean.property 的形式,比如想对按着 book author 中的 title 属性进行排序的时候就可以参考以下的形式:

new BeanComparator

("author.title",severityComparator))

Comparable 接口的实现

       最后如果想对 author 类实现 Comparable 接口可以参考如下的实现:

public class Book implements Comparable {

public int compareTo(Object arg0) {

// comparators setup

String[] severityOrder = { "Critical", "Major", "Minor", "Enhancement" };

// 用于定义一个特殊的顺序,对一组对象按照这样的自定义顺序进行排序;

Comparator severityComparator = new FixedOrderComparator(severityOrder);

ComparatorChain compChain = new ComparatorChain();

       // 通过为属性指定一个已经存在的 Comparator ,而非采用默认的自然顺序

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);

    }

}

   另外一个实现思路是:利用 commons.lang.compareBulder 实现。但是却失去了以上的装饰功能!

 

 

   最后需要说明的是,由于我在工作中最近用到这些排序,所以整理了一下,希望对您有用。同时参考了很多网上的资料,谢!
  

  事例代码我放到了: commons2006@126.com , 密码是 commons2006

 

 

posted on 2006-09-16 16:33 张氏兄弟 阅读(1152) 评论(1)  编辑  收藏

评论:
# re: 关于排序 2006-09-20 13:09 | 坏男孩
哥们,加个友情链接吧  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: