【java】Comparator的用法

文章转载自: http://blog.csdn.net/u012250875/article/details/55126531

1.为什么写?

  1. comparator 是javase中的接口,位于java.util包下,javase中的所有接口抽象度都很高,有必要重视
  2. 网上太多的文章告诉大家comparator是用来排序;确实,可以用来排序,但不仅限于排序
  3. 工作中实际需求出现很多需要使用comparator去处理的问题,在此总结一下。

2.接口功能

该接口的功能表示一个比较器,比较器当然具有可比性!那为什么一百度全是说是用来排序的?这是因为数组工具类和集合工具类中提供的工具方法sort方法都给出了含有Comparator接口的重载方法,大家见久了都只想到Comparator接口是用来排序的,按照java抽象的尿性来看,该接口如果为排序而生,我估计应该叫类似Sortable,Sortor之类的名字吧!下面是javase中该接口的使用原型:

1 Arrays.sort(T[],Comparator<? super T> c);
2 Collections.sort(List<T> list,Comparator<? super T> c);

3.使用场景

考虑什么场景使用该接口就需要考虑什么时候需要比较,比较常用的场景:
1. 排序需要比较,需要比较两个对象谁在前谁在后。
2. 分组需要比较,需要比较两个对象是否是属于同一组。
3. 待补充

4.举个栗子

1.排序
在List或数组中的对象如果没有实现Comparable接口时,那么就需要调用者为需要排序的数组或List设置一个Compartor,Compartor的compare方法用来告诉代码应该怎么去比较两个实例,然后根据比较结果进行排序

talk is cheap show me the code

 1 package com.java.demo;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Collections;
 5 import java.util.Comparator;
 6 import java.util.List;
 7 /**
 8  * @author puyf
 9  */
10 public class SortTest {
11     class Dog{
12     public int age;
13     public String name;
14     public Dog(int age, String name) {
15         super();
16         this.age = age;
17         this.name = name;
18     }
19     @Override
20     public String toString() {
21         return "Dog [age=" + age + ", name=" + name + "]";
22     }
23     }
24     public static void main(String[] args) {
25     List<Dog> list= new ArrayList<>();
26     list.add(new SortTest().new Dog(5, "DogA"));
27     list.add(new SortTest().new Dog(6, "DogB"));
28     list.add(new SortTest().new Dog(7, "DogC"));
29     Collections.sort(list, new Comparator<Dog>() {
30 
31         @Override
32         public int compare(Dog o1, Dog o2) {
33         return o2.age - o1.age;
34         }
35     });
36     System.out.println("给狗狗按照年龄倒序:"+list);
37     Collections.sort(list, new Comparator<Dog>() {
38 
39         @Override
40         public int compare(Dog o1, Dog o2) {
41         return o1.name.compareTo(o2.name);
42         }
43     });
44     System.out.println("给狗狗按名字字母顺序排序:"+list);
45     }
46 }

2.分组
使用Comparator和for循环处理列表,来进行分类;通过调用者实现Comparator接口的比较逻辑,来告诉程序应该怎么比较,通过比较之后得结果来进行分组。比如生活中的拳击比赛,会有公斤级的概念,那么程序中应该实现的处理逻辑是只要两个人的体重在同一个区间则为同一组公斤级的选手。下面例子中分别按照狗狗的颜色和体重级别两个维度来进行分组,因此分组的核心逻辑其实就是比较逻辑。相面我抽了一个工具方法:dividerList,第一个参数为需要处理的数据源,第二参数是分组时的比较逻辑。

 1 package com.java.demo;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Comparator;
 5 import java.util.List;
 6 /**
 7  * @author puyf
 8  */
 9 public class GroupTest {
10     class Apple {
11     public String color;
12     public int weight;
13 
14     public Apple(String color, int weight) {
15         super();
16         this.color = color;
17         this.weight = weight;
18     }
19 
20     @Override
21     public String toString() {
22         return "Apple [color=" + color + ", weight=" + weight + "]";
23     }
24     }
25 
26     /**
27      * @param list 
28      * @param comparator 比较是否为同一组的比较器
29      * @return
30      */
31     public static <T> List<List<T>> dividerList(List<T> list,Comparator<? super T> comparator) {
32     List<List<T>> lists = new ArrayList<>();
33     for (int i = 0; i < list.size(); i++) {
34         boolean isContain = false;
35         for (int j = 0; j < lists.size(); j++) {
36         if (lists.get(j).size() == 0
37             ||comparator.compare(lists.get(j).get(0),     list.get(i)) == 0) {
38             lists.get(j).add(list.get(i));
39             isContain = true;
40             break;
41         }
42         }
43         if (!isContain) {
44         List<T> newList = new ArrayList<>();
45         newList.add(list.get(i));
46         lists.add(newList);
47         }
48     }
49     return lists;
50     }
51 
52     public static void main(String[] args) {
53     List<Apple> list = new ArrayList<>();
54     list.add(new GroupTest().new Apple("红", 205));
55     list.add(new GroupTest().new Apple("红", 131));
56     list.add(new GroupTest().new Apple("绿", 248));
57     list.add(new GroupTest().new Apple("绿", 153));
58     list.add(new GroupTest().new Apple("黄", 119));
59     list.add(new GroupTest().new Apple("黄", 224));
60     List<List<Apple>> byColors = dividerList(list, new Comparator<Apple>() {
61 
62         @Override
63         public int compare(Apple o1, Apple o2) {
64         // 按颜色分组
65         return o1.color.compareTo(o2.color);
66         }
67     });
68     System.out.println("按颜色分组" + byColors);
69     List<List<Apple>> byWeight = dividerList(list, new Comparator<Apple>() {
70 
71         @Override
72         public int compare(Apple o1, Apple o2) {
73         // 按重量级
74 
75         return (o1.weight / 100 == o2.weight / 100) ? 0 : 1;
76         }
77     });
78     System.out.println("按重量级分组" + byWeight);
79     }
80 }

结果如下(为了方便看,手动回车换行格式化了下):
按颜色分组
[
[
Apple [color=红, weight=205],
Apple [color=红, weight=131]
],
[
Apple [color=绿, weight=248],
Apple [color=绿, weight=153]
],
[
Apple [color=黄, weight=119],
Apple [color=黄, weight=224]
]
]

按重量级分组
[
[
Apple [color=红, weight=205],
Apple [color=绿, weight=248],
Apple [color=黄, weight=224]
],
[
Apple [color=红, weight=131],
Apple [color=绿, weight=153],
Apple [color=黄, weight=119]
]
]

5.总结

一般需要做比较的逻辑都可以使用的上Comparator,最常用的场景就是排序和分组,排序常使用Arrays和Collections的sort方法,而分组则可以使用上面提供的dividerList方法。

排序和分组的区别在于:
排序时,两个对象比较的结果有三种:大于,等于,小于。
分组时,两个对象比较的结果只有两种:等于(两个对象属于同一组),不等于(两个对象属于不同组)

原文地址:https://www.cnblogs.com/huaixiaonian/p/7508452.html