实际开发中,我们经常需要对一个实体集合中的实体按照实体的某一个字段进行排序,然后再有序地显示到界面上。例如:我们得到了一个学生集合,而需求要求我们可以按照学生的姓名排序或学生成绩排序。
我们得到的实体集合一般是List或Set类型,所以这里就对二者的排序进行简介。
1、List排序
List集合本身是有序的,所以对它的排序较简单,这里根据List集合元素的类型分为如下两类:
1.1 集合元素可自然排序时
所谓的“可自然排序”,指的是List集合中的元素的类型实现了Comparable<T>接口,如,String类型与Integer类型:
此种类型的List排序很简单,只需要调用Collections.sort(List<T>list)即可对参数中List进行排序,实例如下:
public class TestListSort {
@SuppressWarnings("unchecked")
public static void main(String[] argStrings) {
ArrayList strList = new ArrayList();
ArrayList intList = new ArrayList();
strList.add("b");
strList.add("a");
strList.add("c");
intList.add(2);
intList.add(1);
intList.add(3);
print(intList);// 1.0、排序【前】输出:2 1 3
print(strList);// 1.1、排序【前】输出:b a c
Collections.sort(intList);
Collections.sort(strList);
print(intList);// 2.0、排序【后】输出:1 2 3
print(strList);// 2.1、排序【后】输出:a b c
}
public static void print(List list) {
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
1.2 集合元素【不】可自然排序时
即List集合中的元素的类型【没有】实现Comparable<T>接口,例如为自定义类(Student)。这时需要用Collections.sort(List<T>list, Comparator<? super T> c)进行排序,该方法的核心为第二个参数,即自定义一个排序规则。实例如下:
1、下面我们先自定义一个学生类(Student):
public class Student {
private String stuName;
private int score;
// ------get/set
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
2、然后构造一个List<Student>类型的对象,以及打印方法
public static List<Student> getListStudents() {
List<Student> listStudents = new ArrayList<Student>();
Student stu2 = new Student();
stu2.setStuName("stu2");
stu2.setScore(70);
Student stu1 = new Student();
stu1.setStuName("stu1");
stu1.setScore(50);
Student stu3 = new Student();
stu3.setStuName("stu3");
stu3.setScore(90);
listStudents.add(stu2);
listStudents.add(stu1);
listStudents.add(stu3);
return listStudents;
}
public static void printStuListName(List<Student> list) {
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getStuName());
}
}
3、然后测试按照【姓名】对List<Student>进行排序
public static void main(String[] args) {
List<Student> listStudents = getListStudents();
printStuListName(listStudents);// 1、排序【前】输出:stu2 stu1 stu3
System.out.println("----------------------------------------");
// 自定义排序规则,按照学生的【姓名】进行排序
Collections.sort(listStudents, new Comparator<Student>() {
@Override
public int compare(Student stu1, Student stu2) {
return stu1.getStuName().compareTo(stu2.getStuName());// 按照【姓名】排序
// return stu1.getScore() > stu2.getScore() ? 1 : -1;// 按照【年龄】排序
}
});
printStuListName(listStudents);// 2、按照【姓名】排序【后】输出:stu1 stu2 stu3
}
2、TreeSet排序
在实际项目中,实体关联中有一对多或多对多的关系时,多的一方一般用Set集合(HashSet)表示,所以我们获取到一个实体集合返回到界面时往往也需要根据Set集合中的某个字段排序。实体关联一般用HashSet,但我们知道HashSet本身是无序的,但TreeSet是有序的,所以对HashSet排序的一种思路就是先转为TreeSet再排序,HashSet排序的几种思路将在后面介绍。下面介绍TreeSet的排序。
2.1 排序原理
TreeSet的排序其实与上面的List排序原理大同小异,不同的是, TreeSet在放入(add)元素的时候,(如果集合元素可自然排序)就会自动调用排序方法(compareTo())对集合中的元素进行了排序。而不用手动再调用某一个排序方法。实例如下:
public class TestTreeSetSort {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
// 跟踪源码会发现,当执行TreeSet 的add方法时会自动对里面的元素进行排序
treeSet.add("a");
treeSet.add("c");
treeSet.add("b");
Iterator treeSetIterator = treeSet.iterator();
// 循环输出treeSet内容:a b c
while (treeSetIterator.hasNext()) {
System.out.println(treeSetIterator.next());
}
}
}
下面对一个Student(同1.2中的Student类)的TreeSet集合的排序进行思路分析,一般有两种思路:
2.2 使用TreeSet的默认排序,集合元素实现Comparable接口
即运用上面的TreeSet的默认排序原理,将Student对象放入TreeSet集合时自动排序。
当然一成不变的Student类是不能自动排序的,要想享受这一服务,就需要改造这个Student,让它实现Comparable接口,并重写compareTo()方法,我们即可在该方法中自定义排序规则,代码如下:
2.2.1、改造后的Student类
public class Student implements Comparable {
private String stuName;
private int score;
// 当执行TreeSet<Student>的add()方法时会自动调用该方法进行排序
@Override
public int compareTo(Object obj) {
Student stu = (Student) obj;
return this.stuName.compareTo(stu.getStuName());
}
// ------get/set
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
2.2.2、然后构造一个TreeSet<Student>类型的对象,以及打印方法
public static TreeSet<Student> getTreeSetStudents() {
TreeSet<Student> treeSetStudents = new TreeSet<Student>();
Student stu2 = new Student();
stu2.setStuName("stu2");
stu2.setScore(70);
Student stu1 = new Student();
stu1.setStuName("stu1");
stu1.setScore(50);
Student stu3 = new Student();
stu3.setStuName("stu3");
stu3.setScore(90);
// 当执行add方法时会自动调用Student类的compareTo()方法进行排序
treeSetStudents.add(stu2);
treeSetStudents.add(stu1);
treeSetStudents.add(stu3);
return treeSetStudents;
}
public static void printStuTreeSetName(TreeSet<Student> treeSetStudents) {
for (Student student : treeSetStudents) {
System.out.println(student.getStuName());
}
}
2.2.3、然后测试输出构造的TreeSet<Student>对象,看是否已被排序
public static void main(String[] args) {
TreeSet<Student> treeSetStudents = getTreeSetStudents();
printStuTreeSetName(treeSetStudents);// 输出已排好序的:stu1 stu2 stu3
}
2.3 通过TreeSet(Comparator<? super E>comparator)方法排序
即手动构造TreeSet的比较器进行排序,形式不同,其实原理是一样的,代码如下:
2.3.1、还用原始的学生类(Student):
public class Student {
private String stuName;
private int score;
// ------get/set
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
2.3.2、然后自定义一个排序(比较)类
/**
* @author wangzhipeng
*
*/
public class MyComparator implements Comparator {
@Override
public int compare(Object element1, Object element2) {
Student stu1 = (Student) element1;
Student stu2 = (Student) element2;
int result = stu1.getStuName().compareTo(stu2.getStuName());
return result;
}
}
2.3.3、然后构造一个TreeSet<Student>类型的对象【要将上面的MyComparator的一个对象当做参数传进去】,以及打印方法
public static TreeSet<Student> getTreeSetStudents() {
// 关键点,new 一个TreeSet<Student>对象时,将我们写好的自定义排序类的对象当做参数传进去
TreeSet<Student> treeSetStudents = new TreeSet<Student>(new MyComparator());
Student stu2 = new Student();
stu2.setStuName("stu2");
stu2.setScore(70);
Student stu1 = new Student();
stu1.setStuName("stu1");
stu1.setScore(50);
Student stu3 = new Student();
stu3.setStuName("stu3");
stu3.setScore(90);
// 当执行add方法时会自动调用MyComparator类的 compare(Object element1, Object
// element2)方法进行排序
treeSetStudents.add(stu2);
treeSetStudents.add(stu1);
treeSetStudents.add(stu3);
return treeSetStudents;
}
public static void printStuTreeSetName(TreeSet<Student> treeSetStudents) {
for (Student student : treeSetStudents) {
System.out.println(student.getStuName());
}
}
2.3.4、然后测试输出构造的TreeSet<Student>对象,看是否已被排序
public static void main(String[] args) {
TreeSet<Student> treeSetStudents = getTreeSetStudents();
printStuTreeSetName(treeSetStudents);// 输出已排好序的:stu1 stu2 stu3
}
3、HashSet排序
上面我也提到了,实体关联多的一方一般是用无序的HashSet表示,而不是有序地的TreeSet表示。所以我们下面介绍HashSet的排序思路。
思路很简单,HashSet是无序的,本身肯定不具备排序的功能,所以想要排序就将其转化为上面介绍的两种有序的集合List或TreeSet,代码如下:
3.1、首先获得一个HashSet<Student>类型的对象
public static HashSet<Student> getHashSetStudents() {
HashSet<Student> hashSetStudents = new HashSet<Student>();
Student stu2 = new Student();
stu2.setStuName("stu2");
stu2.setScore(70);
Student stu1 = new Student();
stu1.setStuName("stu1");
stu1.setScore(50);
Student stu3 = new Student();
stu3.setStuName("stu3");
stu3.setScore(90);
// 当执行add方法时会自动调用Student类的compareTo()方法进行排序
hashSetStudents.add(stu2);
hashSetStudents.add(stu1);
hashSetStudents.add(stu3);
return hashSetStudents;
}
3.2、对这个对象进行排序
public static void main(String[] args) {
// 获得一个HashSet<Student>对象
HashSet<Student> hashSetStudents = getHashSetStudents();
// 1、将上面的对象转为一个List<Student>对象,并排序
List<Student> listStudents = new ArrayList<Student>(hashSetStudents);
Collections.sort(listStudents, new Comparator<Student>() {
@Override
public int compare(Student stu1, Student stu2) {
return stu1.getStuName().compareTo(stu2.getStuName());// 按照【姓名】排序
}
});
// 循环输出已排好序的元素:stu1 stu2 stu3
for (Student student : listStudents) {
System.out.println(student.getStuName());
}
// 2、将上面的对象转为一个TreeSet<Student>对象
TreeSet<Student> treeSetStudents = new TreeSet<Student>(new MyComparator());
for (Student student : hashSetStudents) {
treeSetStudents.add(student);
}
// 循环输出已排好序的元素:stu1 stu2 stu3
for (Student student : treeSetStudents) {
System.out.println(student.getStuName());
}
}
4、总结
这几种集合的排序貌似有很多种方式,其实底层实现都可归为一种,无论是调用集合默认的排序方法还是自定义排序方式,其实可以说是一个compare(Object o1,Object o2)方法。