集合排序Comparator和Comparable的使用区别

Comparable可以认为是一个内比较器,而Comparator可以认为是一个外比较器。下面看一下如何进行集合排序,常用的方法有: ComparatorComparable

一、Comparator接口

Comparator可以认为是是一个外比较器,在比较的Bean上不用做任何改变,但是需要新建一个比较类实现Comparator接口并重写compare方法

自定义类使用步骤:

  1. 新建比较类,
  2. 实现Comparator接口,
  3. 重写compare方法

通过Collections.sort排序

1
2
3
4
5
6
7
8
9
10
11
package sort; 

import java.util.Comparator;

public class LuckBoyCompare implements Comparator<LuckBoy>{

@Override
public int compare(LuckBoy o1, LuckBoy o2) {
return o1.getAge()-o2.getAge(); //前减后,升序
}
}
  • 调用Collections.sort()方法进行排序,
  • 形式:Collections.sort(集合, 比较器实例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class MyTest {
private List<LuckBoy> boyList = new ArrayList<LuckBoy>();

@Before
public void init(){
LuckBoy boy1 = new LuckBoy("张三",13,"上海");
LuckBoy boy2 = new LuckBoy("李四",12,"北京");
LuckBoy boy3 = new LuckBoy("王五",18,"深圳");
LuckBoy boy4 = new LuckBoy("马六",17,"南京");

boyList.add(boy1);
boyList.add(boy2);
boyList.add(boy3);
boyList.add(boy4);

System.out.println("排序前:");
for (LuckBoy luckBoy : boyList) {
System.out.println(luckBoy);
}
}

//通过Comparator类排序
@Test
public void test1() {
System.out.println("test1排序后:");

Collections.sort(boyList, new LuckBoyCompare());
for (LuckBoy luckBoy : boyList) {
System.out.println(luckBoy);
}
}

//通过匿名Comparator接口实现排序
@Test
public void test2() { //test1()和test2()效果一样
System.out.println("test2排序后:");

Collections.sort(boyList, new Comparator<LuckBoy>(){
public int compare(LuckBoy a1,LuckBoy a2){
return a1.getAge()-a2.getAge();
}
});

for (LuckBoy luckBoy : boyList) {
System.out.println(luckBoy);
}
}

}

test1输出:

1
2
3
4
5
6
7
8
9
10
排序前:
LuckBoy [name=张三, age=13, city=上海]
LuckBoy [name=李四, age=12, city=北京]
LuckBoy [name=王五, age=18, city=深圳]
LuckBoy [name=马六, age=17, city=南京]
test1排序后:
LuckBoy [name=李四, age=12, city=北京]
LuckBoy [name=张三, age=13, city=上海]
LuckBoy [name=马六, age=17, city=南京]
LuckBoy [name=王五, age=18, city=深圳]

test2输出:

1
2
3
4
5
6
7
8
9
10
排序前:
LuckBoy [name=张三, age=13, city=上海]
LuckBoy [name=李四, age=12, city=北京]
LuckBoy [name=王五, age=18, city=深圳]
LuckBoy [name=马六, age=17, city=南京]
test2排序后:
LuckBoy [name=李四, age=12, city=北京]
LuckBoy [name=张三, age=13, city=上海]
LuckBoy [name=马六, age=17, city=南京]
LuckBoy [name=王五, age=18, city=深圳]

Bean类如下(不用实现任何接口):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package sort; 

public class LuckBoy{
private String name;
private Integer age;
private String city;

public LuckBoy() {
super();
}

public LuckBoy(String name, Integer age, String city) {
super();
this.name = name;
this.age = age;
this.city = city;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}

@Override
public String toString() {
return "LuckBoy [name=" + name + ", age=" + age + ", city=" + city + "]";
}
}

通过Arrays.sort排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//通过Arrays.sort排序
@Test
public void test3() {
LuckBoy[] luckArr=new LuckBoy[4];
luckArr[0] = new LuckBoy("张三",13,"上海");
luckArr[1] = new LuckBoy("李四",12,"北京");
luckArr[2] = new LuckBoy("王五",18,"深圳");
luckArr[3] = new LuckBoy("马六",17,"南京");


System.out.println("test3排序后:");

Arrays.sort(luckArr,new LuckBoyCompare());

for (LuckBoy luckBoy : luckArr) {
System.out.println(luckBoy);
}
}

//通过Arrays.sort排序,并匿名Comparator接口实现排序
@Test
public void test4() {
LuckBoy[] luckArr=new LuckBoy[4];
luckArr[0] = new LuckBoy("张三",13,"上海");
luckArr[1] = new LuckBoy("李四",12,"北京");
luckArr[2] = new LuckBoy("王五",18,"深圳");
luckArr[3] = new LuckBoy("马六",17,"南京");


System.out.println("test4排序后:");

Arrays.sort(luckArr,new Comparator<LuckBoy>(){
public int compare(LuckBoy a1,LuckBoy a2){
return a1.getAge()-a2.getAge();
}
});

for (LuckBoy luckBoy : luckArr) {
System.out.println(luckBoy);
}
}

输出

1
2
3
4
5
6
7
8
9
10
test3排序后:
LuckBoy [name=李四, age=12, city=北京]
LuckBoy [name=张三, age=13, city=上海]
LuckBoy [name=马六, age=17, city=南京]
LuckBoy [name=王五, age=18, city=深圳]
test4排序后:
LuckBoy [name=李四, age=12, city=北京]
LuckBoy [name=张三, age=13, city=上海]
LuckBoy [name=马六, age=17, city=南京]
LuckBoy [name=王五, age=18, city=深圳]

二、Comparable接口

Comparable可以认为是一个内比较器,在要比较的Bean上需要实现Comparable接口并重写其compareTo方法才行。

使用步骤:

  1. 新建Bean
  2. 实现Comparable接口,
  3. 重写compareTo方法,

通过Collections.sort排序

新建Bean并实现Comparable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package sort;

public class MyBoy implements Comparable<MyBoy>{
@Override
public int compareTo(MyBoy o) {
return this.age-o.age; //内部对象-外部,升序
}


private String name;
private Integer age;
private String city;

public MyBoy() {

}

public MyBoy(String name, Integer age, String city) {
this.name = name;
this.age = age;
this.city = city;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}

@Override
public String toString() {
return "LuckBoy [name=" + name + ", age=" + age + ", city=" + city + "]";
}
}
  • 调用Collections.sort()方法进行排序,
  • 形式:Collections.sort(集合)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MyTest2 {
private List<MyBoy> boyList = new ArrayList<MyBoy>();

@Before
public void init(){
MyBoy boy1 = new MyBoy("张三",13,"上海");
MyBoy boy2 = new MyBoy("李四",12,"北京");
MyBoy boy3 = new MyBoy("王五",18,"深圳");
MyBoy boy4 = new MyBoy("马六",17,"南京");

boyList.add(boy1);
boyList.add(boy2);
boyList.add(boy3);
boyList.add(boy4);

System.out.println("排序前:");
for (MyBoy MyBoy : boyList) {
System.out.println(MyBoy);
}
}

@Test
public void test1() {
System.out.println("test1排序后:");
Collections.sort(boyList);
for (MyBoy MyBoy : boyList) {
System.out.println(MyBoy);
}
}
}

通过Arrays.sort排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void test2(){
System.out.println("test2排序后:");
MyBoy[] boyArr=new MyBoy[4];
boyArr[0] = new MyBoy("张三",13,"上海");
boyArr[1] = new MyBoy("李四",12,"北京");
boyArr[2] = new MyBoy("王五",18,"深圳");
boyArr[3] = new MyBoy("马六",17,"南京");

Arrays.sort(boyArr);
for (MyBoy MyBoy : boyArr) {
System.out.println(MyBoy);
}
}

输出:

1
2
3
4
5
test2排序后:
LuckBoy [name=李四, age=12, city=北京]
LuckBoy [name=张三, age=13, city=上海]
LuckBoy [name=马六, age=17, city=南京]
LuckBoy [name=王五, age=18, city=深圳]

三、Comparator自定义数组比较规则

先看两个小例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
//例子一
int[] arr1={5,2,3,1,4};
Arrays.sort(arr1);//默认升序

for(int t:arr1)
System.out.print(t+" ");
System.out.println();

//例子二
int[] arr2={5,2,3,1,4};
Arrays.sort(arr2,0,3);//对arr2[0...2]升序
for(int t:arr2)
System.out.print(t+" ");

输出:

1
2
1 2 3 4 5 
2 3 5 1 4

实验一

1
2
3
4
5
6
7
8
9
int[] arr3={5,2,3,1,4};
//报错,说明不能对一维数组用Comparator
Arrays.sort(arr3,new Comparator<Integer>(){
@Override
public int compare(Integer a1, Integer a2) {
// TODO Auto-generated method stub
return a2-a1;//降序
}
});

实验二

1
2
3
4
5
6
7
8
9
10
int[][] arr4={{3,2},{4,1},{5,4},{3,4}};
Arrays.sort(arr4,new Comparator<int[]>(){ //一定要注意这个类型
public int compare(int[] a1,int[] a2){
//按照数组的第一个值升序,如果第一个值相等,则按照第二个值降序
return a1[0]==a2[0]?a2[1]-a1[1]:a1[0]-a2[0];
}
});
for(int[] a:arr4){
System.out.println(a[0]+"\t"+a[1]);
}

输出:

1
2
3
4
3	4
3 2
4 1
5 4

再来一个小例子:

1
2
3
4
5
6
7
8
9
10
int[][] arr={{3,1},{2,4},{1,3},{2,2},{3,1}};
Arrays.sort(arr,0,3,new Comparator<int[]>(){ //对二维数组中[0..3)的元素排序,注意是左闭右开
public int compare(int[] a,int[] b){
return a[0]==b[0]?b[1]-a[1]:a[0]-b[0];
}
});

for(int[] a:arr){
System.out.println(a[0]+"\t"+a[1]);
}

输出:

1
2
3
4
5
1	3
2 4
3 1
2 2
3 1

四、小结

  • Collections.sort排序的是容器
  • Arrays.sort排序的是普通数组
  • 如果是Bean,一定要可比较,即要么用Comparator,要么用Comparable
  • 因为Comparator是外部的,可以通过匿名实现接口的形式,这样就不用新建一个比较类了