java排序方法对任意类型排序_使用Comparable和Comparator对Java集合对象进行排序

在现实生活中,我们可能会遇到需要对集合内的对象进行排序的场景,比如,

有一个游戏得分排行榜,如先按照分数的高低由高到低排序,在分数相同的情况下,按照记录创建的时间由早到新的顺序排序。

在Java语言中,要实现集合内对象的排序,咱们可以采用两种方式来完成:

使用Comparable来实现

使用Comparator来实现

接下来,我们先使用Comparable和Comparator、结合示例来完成集合内对象排序的功能,然后,对这两种方式进行比较;最后,结合多属性排序的话,给出相对较好的实践方法。

使用Comparable实现

编写游戏记录类GameRecord,然后实现Comparable接口#compareTo方法。

public int compareTo(T o);

具体代码如下:

import java.util.Date;

import org.apache.http.client.utils.DateUtils;

/**

* @author wangmengjun

*

*/

public class GameRecord implements Comparable {

/**玩家名称*/

private String name;

/**记录创建时间*/

private Date createTime;

/**得分*/

private int score;

/**

* @param name

* @param createTime

* @param score

*/

public GameRecord(String name, Date createTime, int score) {

this.name = name;

this.createTime = createTime;

this.score = score;

}

/**

* @return the name

*/

public String getName() {

return name;

}

/**

* @param name the name to set

*/

public void setName(String name) {

this.name = name;

}

/**

* @return the createTime

*/

public Date getCreateTime() {

return createTime;

}

/**

* @param createTime the createTime to set

*/

public void setCreateTime(Date createTime) {

this.createTime = createTime;

}

/**

* @return the score

*/

public int getScore() {

return score;

}

/**

* @param score the score to set

*/

public void setScore(int score) {

this.score = score;

}

/* (non-Javadoc)

* @see java.lang.Object#toString()

*/

@Override

public String toString() {

return "GameRecord [name=" + name + ", createTime="

+ DateUtils.formatDate(createTime, "yyyy-MM-dd HH:mm:ss") + ", score=" + score

+ "]";

}

/* (non-Javadoc)

* @see java.lang.Comparable#compareTo(java.lang.Object)

*/

@Override

public int compareTo(GameRecord other) {

int scoreComapre = Integer.compare(other.getScore(), score);

/**

* 先按照分数从高到低排列,

* 如果分数一样,按照记录创建的时间排序

*/

if (scoreComapre == 0) {

return createTime.compareTo(other.getCreateTime());

}

return scoreComapre;

}

}

当GameRecord类实现Comparable接口之后,该类对象就具有比较的功能了,然后我们要做的就是对GameRecord对象的集合类进行排序即可,集合的排序可以采用java.util.Collections类的sort方法完成。

代码示例如下:

import java.util.Arrays;

import java.util.Collection;

import java.util.Collections;

import java.util.Date;

import java.util.List;

import org.apache.commons.httpclient.util.DateParseException;

import org.apache.commons.httpclient.util.DateUtil;

import org.apache.http.client.utils.DateUtils;

/**

* @author wangmengjun

*

*/

public class Main {

/**

* 可用于转换的日期格式集合

*/

private static final Collection AVAILABLE_DATE_FORMATTERS = Arrays

.asList("yyyy-MM-dd HH:mm:ss");

public static void main(String[] args) throws DateParseException {

Date d1 = DateUtil.parseDate("2015-12-31 00:22:30", AVAILABLE_DATE_FORMATTERS);

Date d2 = DateUtil.parseDate("2016-05-11 12:56:01", AVAILABLE_DATE_FORMATTERS);

Date d3 = DateUtil.parseDate("2016-05-11 12:56:01", AVAILABLE_DATE_FORMATTERS);

GameRecord r1 = new GameRecord("Wang", d1, 300);

GameRecord r2 = new GameRecord("Meng", d2, 100);

GameRecord r3 = new GameRecord("Jun", d3, 300);

List records = Arrays.asList(r3, r2, r1);

System.out.println("排序前的结果==>");

//System.out.println(records);

printGameRecordInfo(records);

Collections.sort(records);

System.out.println("排序后的结果==>");

printGameRecordInfo(records);

}

private static void printGameRecordInfo(Collection records) {

for (GameRecord record : records) {

System.out.println(String.format("%s\t%d\t%s",

DateUtils.formatDate(record.getCreateTime(), "yyyy-MM-dd HH:mm:ss"),

record.getScore(), record.getName()));

}

}

}

运行结果如下:

排序前的结果==>

2016-05-11 12:56:01300Jun

2016-05-11 12:56:01100Meng

2015-12-31 00:22:30300Wang

排序后的结果==>

2015-12-31 00:22:30300Wang

2016-05-11 12:56:01300Jun

2016-05-11 12:56:01100Meng

使用Comparator来实现

如果采用Comparator来实现,那么实体类GameRecord类无需实现Comparable接口,无需改变实体类的内容。

我们要做的就是建立一个外部的Comparator即可。实体类GameRecord和外部Compartor代码如下:

import java.util.Date;

import org.apache.http.client.utils.DateUtils;

/**

* @author wangmengjun

*

*/

public class GameRecord {

/**玩家名称*/

private String name;

/**记录创建时间*/

private Date createTime;

/**得分*/

private int score;

/**

* @param name

* @param createTime

* @param score

*/

public GameRecord(String name, Date createTime, int score) {

this.name = name;

this.createTime = createTime;

this.score = score;

}

/**

* @return the name

*/

public String getName() {

return name;

}

/**

* @param name the name to set

*/

public void setName(String name) {

this.name = name;

}

/**

* @return the createTime

*/

public Date getCreateTime() {

return createTime;

}

/**

* @param createTime the createTime to set

*/

public void setCreateTime(Date createTime) {

this.createTime = createTime;

}

/**

* @return the score

*/

public int getScore() {

return score;

}

/**

* @param score the score to set

*/

public void setScore(int score) {

this.score = score;

}

/* (non-Javadoc)

* @see java.lang.Object#toString()

*/

@Override

public String toString() {

return "GameRecord [name=" + name + ", createTime="

+ DateUtils.formatDate(createTime, "yyyy-MM-dd HH:mm:ss") + ", score=" + score

+ "]";

}

}

比较器GameRecordComparator实现Comparator接口,然后实现Comparator的compare方法:

先比较分数(从高到低),如果分数一致,那么比较记录创建时间 (从早到新)

public int compare(GameRecord r1, GameRecord r2) {

int scoreCompare = Integer.compare(r2.getScore(), r1.getScore());

return scoreCompare == 0 ? r1.getCreateTime().compareTo(r2.getCreateTime()) : scoreCompare;

}

GameRecordComparator类的详细代码如下:

import java.util.Comparator;

/**

* @author wangmengjun

*

*/

public class GameRecordComparator implements Comparator {

/* (non-Javadoc)

* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)

*/

@Override

public int compare(GameRecord r1, GameRecord r2) {

int scoreCompare = Integer.compare(r2.getScore(), r1.getScore());

return scoreCompare == 0 ? r1.getCreateTime().compareTo(r2.getCreateTime()) : scoreCompare;

}

}

然后,我们就可以直接调用java.util.Collections类的sort方法完成排序,java.util.Collections类的sort方法源码如下:

public static void sort(List list, Comparator super T> c) {

Object[] a = list.toArray();

Arrays.sort(a, (Comparator)c);

ListIterator i = list.listIterator();

for (int j=0; j

i.next();

i.set(a[j]);

}

}

测试代码如下:

import java.util.Arrays;

import java.util.Collection;

import java.util.Collections;

import java.util.Date;

import java.util.List;

import org.apache.commons.httpclient.util.DateParseException;

import org.apache.commons.httpclient.util.DateUtil;

import org.apache.http.client.utils.DateUtils;

/**

* @author wangmengjun

*

*/

public class Main {

/**

* 可用于转换的日期格式集合

*/

private static final Collection AVAILABLE_DATE_FORMATTERS = Arrays

.asList("yyyy-MM-dd HH:mm:ss");

public static void main(String[] args) throws DateParseException {

Date d1 = DateUtil.parseDate("2015-12-31 00:22:30", AVAILABLE_DATE_FORMATTERS);

Date d2 = DateUtil.parseDate("2016-05-11 12:56:01", AVAILABLE_DATE_FORMATTERS);

Date d3 = DateUtil.parseDate("2016-05-11 12:56:01", AVAILABLE_DATE_FORMATTERS);

GameRecord r1 = new GameRecord("Wang", d1, 300);

GameRecord r2 = new GameRecord("Meng", d2, 100);

GameRecord r3 = new GameRecord("Jun", d3, 300);

List records = Arrays.asList(r3, r2, r1);

System.out.println("排序前的结果==>");

//System.out.println(records);

printGameRecordInfo(records);

Collections.sort(records, new GameRecordComparator());

System.out.println("排序后的结果==>");

printGameRecordInfo(records);

}

private static void printGameRecordInfo(Collection records) {

for (GameRecord record : records) {

System.out.println(String.format("%s\t%d\t%s",

DateUtils.formatDate(record.getCreateTime(), "yyyy-MM-dd HH:mm:ss"),

record.getScore(), record.getName()));

}

}

}

运行结果如下:

排序前的结果==>

2016-05-11 12:56:01300Jun

2016-05-11 12:56:01100Meng

2015-12-31 00:22:30300Wang

排序后的结果==>

2015-12-31 00:22:30300Wang

2016-05-11 12:56:01300Jun

2016-05-11 12:56:01100Meng

通过上面的代码,我们完成了使用Comparable以及Comparator实现对象集合排序的示例,接下来,我们来简单分析一下Comparable和Comparator的区别。

Comparable和Comparator区别

采用Comparable的方法,该方法从类的内部实现对象的比较。采用Comparator的方法,是一种类外部的实现,不需要对需要排序的类(如GameRecord)进行改变,保持原有状态即可。

采用Comparable的方法,因为是类内部实现的,其排序的方式只有一种方式。采用Comparator的方法,因为是外部编写比较器实现的,所以会更加灵活。我们可以编写多种比较器,完成不一样的排序。

比如:

游戏分数比较器

import java.util.Comparator;

/**

* @author wangmengjun

*

*/

public class ScoreComparator implements Comparator {

/* (non-Javadoc)

* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)

*/

@Override

public int compare(GameRecord r1, GameRecord r2) {

return Integer.compare(r2.getScore(), r1.getScore());

}

}

Collections.sort(records, new ScoreComparator());

排序前的结果==>

2016-05-11 12:56:01300Jun

2016-05-11 12:56:01100Meng

2015-12-31 00:22:30300Wang

排序后的结果==>

2016-05-11 12:56:01300Jun

2015-12-31 00:22:30300Wang

2016-05-11 12:56:01100Meng

游戏记录创建时间比较器

import java.util.Comparator;

/**

* @author wangmengjun

*

*/

public class CreateTimeComparator implements Comparator {

/* (non-Javadoc)

* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)

*/

@Override

public int compare(GameRecord r1, GameRecord r2) {

return r1.getCreateTime().compareTo(r2.getCreateTime());

}

}

Collections.sort(records, new CreateTimeComparator());

排序前的结果==>

2016-05-11 12:56:01300Jun

2016-05-11 12:56:01100Meng

2015-12-31 00:22:30300Wang

排序后的结果==>

2015-12-31 00:22:30300Wang

2016-05-11 12:56:01300Jun

2016-05-11 12:56:01100Meng

Comparator适用场景

如果不想改变原来类的状态,添加排序功能,可以使用Comparator来做。如果有多种排序策略,可以采用Comparator来做。

多属性排序方法

在上述示例中,我们采用先按照分数排序(降序),然后如果分数相等,按照记录的创建日期排序(升序)。以GameRecordComparator的compare方法为例:

public int compare(GameRecord r1, GameRecord r2) {

int scoreCompare = Integer.compare(r2.getScore(), r1.getScore());

return scoreCompare == 0 ? r1.getCreateTime().compareTo(r2.getCreateTime()) : scoreCompare;

}

如果属性比较多,假设在分数和记录创建时间之外还需要对名称等字段进行比较,那么compare方法中,我们需要一个个地对各个属性字段逐个比较,这样写的越多,我们的if语句或者三元运算符逻辑就会增多。

有没有更加简便的方式来完成多属性排序呢?答案是肯定的。

下面我们就采用CompareToBuilder以及ComparisonChain来完成。

使用org.apache.commons.lang.builder.CompareToBuilder完成多属性排序

public int compare(GameRecord r1, GameRecord r2) {

return new CompareToBuilder().append(r2.getScore(), r1.getScore())

.append(r1.getCreateTime(), r2.getCreateTime())

.toComparison();

}

使用com.google.common.collect.ComparisonChain完成多属性排序

public int compare(GameRecord r1, GameRecord r2) {

return ComparisonChain.start().compare(r2.getScore(), r1.getScore())

.compare(r1.getCreateTime(), r2.getCreateTime()).result();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值