一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

java中利用Comparator进行复杂对象Collection的排序

时间:2013-11-27 编辑:简简单单 来源:一聚教程网

需求场景描述:

需要对一个Collection进行某种方式的排序。比如一个User对象的集合,我们需要按公司和姓名进行排序。User对象如下:

 代码如下 复制代码

package com.guoweiwei.test.comparator;
public class User {

private String name;

private String sex;

private String company;

User(){};

User(String name, String sex, String company){

this.name = name;

this.sex = sex;

this.company = company;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getSex() {

return sex;

}

public void setSex(String sex) {

this.sex = sex;

}

public void setCompany(String company) {

this.company = company;

}

public String getCompany() {

return company;

}

}

解决方案:

一般简单的排序,我们用现有的排序算法就可以解决了。但是对于复杂的排序,比如根据公司名称、职位、工号等信息排序的话,那往往是不够的。这就需要我们实现Comparator接口,通过该接口进行比较。Comparator接口只定义了一个方法compare,该方法根据一定的策略比较两个对象,然后返回一个整数值。如下为该接口的定义:

 代码如下 复制代码

int compare(T o1, T o2);

如果o1小于o2,返回-1;o1等于o2,返回0;o1大于o2,返回1。

根据这个原理,我们实现如下的Comparator接口代码:

 代码如下 复制代码

package com.guoweiwei.test.comparator;
import java.util.Comparator;

public class UserComparator implements Comparator {

@Override

public int compare(User user1, User user2){

int comparison = -1;

String company1 = user1.getCompany();

String company2 = user2.getCompany();

String name1 = user1.getName();

String name2 = user2.getName();

if(company1.length() != 0 && company2.length() != 0){

comparison = company1.compareTo(company2);

}

/*在公司名称相同的前提下,根据姓名比较*/

if(comparison ==0 && name1.length() != 0 && name2.length() != 0){

comparison = name1.compareTo(name2);

}

return comparison;

}

}

有了这个比较器,我们就可以根据这个比较器对User列表进行排序,返回值是根据公司名称和用户姓名进行排序的Array或List对象。看一下我们的比较代码:

 代码如下 复制代码

@SuppressWarnings("unchecked")
public static void startCompare(){

User user1 = new User("A","男","AA");

User user2 = new User("A","男","BB");

User user3 = new User("B","女","AA");

User user4 = new User("B","男","BB");

User user5 = new User("C","男","BB");

User[] users = new User[]{user1,user2,user3,user4,user5};

Comparator userComparator = new UserComparator();

Arrays.sort(users,userComparator);

for(User user : users){

System.out.println(user.getCompany() + " " + user.getName() + " " + user.getSex());

}

}

运行程序,我们将得到如下的结果:

AA A 男
AA B 女
BB A 男
BB B 男
BB C 男

有没有更简单的实现方式呢?回答是肯定的,那就是用ComparatorChain。ComparatorChain把若干个Comparator对象连起来,组成一个Comparator链。在比较两个对象的时候,依次用这个Comparator链中的每个Comparator进行比较,直到有一个Comparator返回非零值则结束比较;如果相等,则继续用该链中的下一个Comparator比较。如下代码所示:

 代码如下 复制代码

@SuppressWarnings("unchecked")
public static void start(){

User user1 = new User("A","男","AA");

User user2 = new User("A","男","BB");

User user3 = new User("B","女","AA");

User user4 = new User("B","男","BB");

User user5 = new User("C","男","BB");

User[] users = new User[]{user1,user2,user3,user4,user5};

ComparatorChain comparatorChain = new ComparatorChain();

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

comparatorChain.addComparator(new BeanComparator("sex"),true);

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

Arrays.sort(users,comparatorChain);

for(User user : users){

System.out.println(user.getName() + " " + user.getSex() + " " + user.getCompany());

}

}

运行程序,我们将得到如下的结果:

A 男 AA
A 男 BB
B 男 BB
B 女 AA
C 男 BB

这里要说明的两点是:①ComparatorChain来自commons.collections这个包,BeanComparator 来自commons.beanutils这个包,所以一定要引用这两个包才行。②对于comparatorChain.addComparator()方法中的第二个参数,其含义是是否反转(也就是为true就倒序,默认是升序)。

需求升级:

更进一步,大家或许有疑问了。这B公司的AA和BB好像不对啊,这个中文是依据什么排序的呢?按性别倒过来应该是女、男才对啊。到这一步,我也说不上来,因为我不懂这里的中文是根据什么来排序的。那面对中文该怎么办呢?

还好,有很多中文工具可以帮我们实现,比较常见的有Collator和pinyin4j。Collator是JDK自带的一个本地化工具,pinyin4j是google上的一个开源项目。以Collator实现的中文排序Comparator如下:

 代码如下 复制代码

public class ChineseComparator implements Comparator {
private final static Collator collator = Collator.getInstance(Locale.CHINESE);

@Override

public int compare(String str1, String str2){

int comparison = -1;

if(str1 == null && str2 == null){

comparison = 0;

}elseif(str1 == null){

comparison = -1;

}elseif(str2 == null){

comparison = 1;

}else{

CollationKey key1 = collator.getCollationKey(str1);

CollationKey key2 = collator.getCollationKey(str2);

comparison = key1.compareTo(key2);

}

return comparison;

}

}

将需要排序的User数组和Comparator装饰改为如下:

 代码如下 复制代码

@SuppressWarnings("unchecked")
public static void start(){

User user1 = new User("马加爵","男","招商局");

User user2 = new User("李刚","男","公安局");

User user3 = new User("马加爵","女","招商局");

User user4 = new User("李英","男","公安局");

User user5 = new User("马加爵","男","公安局");

User[] users = new User[]{user1,user2,user3,user4,user5};

Comparator chineseComparator = new ChineseComparator();

ComparatorChain comparatorChain = new ComparatorChain();

comparatorChain.addComparator(new BeanComparator("company",chineseComparator));

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

comparatorChain.addComparator(new BeanComparator("sex",chineseComparator));

Arrays.sort(users,comparatorChain);

for(User user : users){

System.out.println(user.getCompany() + " " + user.getName() + " " + user.getSex());

}

}

}

运行代码,得到如下结果:

公安局 李刚 男
公安局 李英 男
公安局 马加爵 男
招商局 马加爵 男
招商局 马加爵 女

延伸阅读:

对null的比较:

 代码如下 复制代码
Comparator userComparator = new UserComparator();
Comparator nullComparator = new NullComparator(userComparator,true);

固定顺序的比较:

 代码如下 复制代码
String[] weeks = {"星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
Comparator fixedComparator = new FixedOrderComparator(weeks);
Comparator weeksComparator = new BeanComparator("week",fixedComparator);

热门栏目