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

需求场景描述:

需要对一个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<User> {

@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<String> {
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);
时间: 2024-09-29 14:43:12

java中利用Comparator进行复杂对象Collection的排序的相关文章

浅谈Java中常用数据结构的实现类 Collection和Map_java

线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以及如何正确使用这些类. Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └WeakHashMap Collection接口 Collection是最基本的集合接口,一个C

Java中利用散列表实现股票行情的查询(转)

Java中利用散列表实现股票行情的查询 建设银行云南省保山地区分行 杨绍方 ---- 在java中,提供了一个散列表类Hashtable,利用该类,我们可以按照特定的方式来存储数据,从而达到快速检索的目的.本文以查询股票的收盘数据为例,详细地说明java中散列表的使用方法.一.散列表的原理 ---- 散列表,又称为哈希表,是线性表中一种重要的存储方式和检索方法.在散列表中,可以对节点进行快速检索.散列表算法的基本思想是:由结点的关键码值决定结点的存储地址,即以关键码值k为自变量,通过一定的函数关

Android中利用C++处理Bitmap对象的实现方法

相信有些Android&图像算法开发者和我一样,遇到过这样的状况:要对Bitmap对象做一些密集计算(例如逐像素的滤波),但是在java层写循环代码来逐像素操作明显是不现实的,因为Java代码的运行速度太慢,而一副很小的240*320图像就有76800个像素,如果考虑到RGB三通道(或者ARGB四通道),还要对这个数量乘以3/4.因此对图像的密集计算一般都利用Jni接口,用C++实现.那么问题来了,怎么把Bitmap中的像素数据从Java层传到C++层? 做法1:之前的做法 我之前的做法是这样的

第三方dll文件-Java中利用jawin调用dll文件,invoke的参数问题

问题描述 Java中利用jawin调用dll文件,invoke的参数问题 各位大神: dll中的被调用方法如下: long WINAPI AutoOpenComPort(long* Port, unsigned char *ComAdr, unsigned char Baud,long *FrmHandle); 其中: Port:输出变量, ComAdr:输入/输出变量 Baud:输入变量 FrmHandle:输出变量 请问它的 msgBox.invoke(instructions, stack

在java中如何获取或初始化scala.collection.immutable.Map?

问题描述 在java中如何获取或初始化scala.collection.immutable.Map? java调用kafka API时需要一个一个scala.collection.immutable.Map参数,但不知道如何初始化或通过其他API获取 解决方案 java.util.Map javaMap = new java.util.HashMap();scala.collection.immutable.Map scalaImmutableMap = scala.collection.Jav

Java中Json字符串直接转换为对象的方法(包括多层List集合)_java

使用到的类:net.sf.json.JSONObject  使用JSON时,除了要导入JSON网站上面下载的json-lib-2.2-jdk15.jar包之外,还必须有其它几个依赖包:commons-beanutils.jar,commons-httpclient.jar,commons-lang.jar,ezmorph.jar,morph-1.0.1.jar 下面是例子代码: // JSON转换 JSONObject jsonObj = JSONObject.fromObject(jsonSt

工厂模式-java中工厂实例就是工厂对象对吗,和普通实例普通对象有什么区别

问题描述 java中工厂实例就是工厂对象对吗,和普通实例普通对象有什么区别 java中工厂实例就是工厂对象对吗,和普通实例普通对象有什么区别 解决方案 工厂实例就是这个工厂类的一个对象,跟普通实例对象没有什么区别的. 主要就是这个工厂实例的作用就是创建某种类型的对象的.即生产什么的工厂.

java中getA( ).getB( )意思就是 对象.对象那结果是什么

问题描述 java中getA( ).getB( )意思就是 对象.对象那结果是什么 java中getA( ).getB( )意思就是 对象.对象那结果是什么 结果还是一个对象么, 是不是子对象和父对象的意思呢 java没有这样的概念吧,应该如何理解呢 解决方案 这个要看 getA( ) 和 getB( ) 的具体实现,不能依赖于函数名来判断功能. 解决方案二: public class T2 { public static void main(String[] args) { new T2().

数据库-java中什么类,什么对象,什么方法,什么语句读取sql表文件的数据的

问题描述 java中什么类,什么对象,什么方法,什么语句读取sql表文件的数据的 java中什么类,什么对象,什么方法,什么语句读取sql表文件的数据的 解决方案 Statement或者preparedStatement类对应的实体对象,使用executeUpdate方法执行sql语句的查询操作.executeUpdate方法执行其他sql操作 解决方案二: http://blog.csdn.net/csh624366188/article/details/7305672/ 解决方案三: 这三个