# Java `Comparator`接口示例

> 原文： [https://howtodoinjava.com/java/collections/java-comparator/](https://howtodoinjava.com/java/collections/java-comparator/)

**Java 比较器**接口，用于根据**自定义顺序**对对象的[数组](https://howtodoinjava.com/java-array/)或[列表](https://howtodoinjava.com/java-arraylist/)进行排序。 通过在对象中实现`Comparator.compare()`方法来强加元素的自定义顺序。

## 1\. Java `Comparator`接口

Java `Comparator`接口在可能没有自然顺序的对象上强加了**自定义顺序**。

例如，对于`Elpmoyees`对象的列表，自然顺序可以是按员工 ID 排序的顺序。 但是在现实生活中，我们可能希望按照员工的名字，出生日期或其他任何类似标准对员工列表进行排序。 在这种情况下，我们需要使用`Comparator`接口。

在以下情况下，我们可以使用`Comparator`接口。

1.  对对象的数组或列表进行排序，但不按自然顺序排序。
2.  在无法修改对象源代码以实现[`Comparable`](https://howtodoinjava.com/java/collections/java-comparable-interface/)接口的情况下，对对象的数组或列表进行排序。
3.  在不同字段上对相同对象列表或对象数组进行排序。
4.  在不同字段上对对象列表或数组进行分组排序。

#### 1.1\. `Comparator.compare()`

为了对对象启用总体排序，我们需要创建实现`Comparator`接口的类。 然后，我们需要覆盖它的`compare(T o1, T o2)`方法。

它比较两个参数的顺序。 当第一个参数小于，等于或大于第二个参数时，它将返回负整数，零或正整数。

实现者还必须确保该关系是**可传递的**：`compare(x, y)>0 && compare(y, z)>0`隐含`compare(x, z)>0`。

```java
import java.time.LocalDate;

public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;
    private String name;
    private LocalDate dob;

    //Getters and Setters

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", dob=" + dob + "]";
    }
}

```

对于以上类别，可以通过创建如下的`Comparator`来强行按员工姓名排序。

```java
import java.util.Comparator;

public class NameSorter implements Comparator<Employee>
{
    @Override
    public int compare(Employee e1, Employee e2) {
        return e1.getName().compareToIgnoreCase( e2.getName() );
    }
}

```

#### 1.2 `Collections.sort()`和`Arrays.sort()`

1.  使用`Collections.sort(list, Comparator)`方法按提供的比较器实例施加的顺序对对象的**列表**进行排序。
2.  使用`Arrays.sort(array, Comparator)`方法按提供的比较器实例施加的顺序对对象的**数组**进行排序。

#### 1.3 `Collections.comparing()`

该工具方法接受一个为类提取排序键的函数。 本质上，这是一个将对类对象进行排序的字段。

```java
//Order by name
Comparator.comparing(Employee::getName);

//Order by name in reverse order
Comparator.comparing(Employee::getName).reversed();

//Order by id field
Comparator.comparing(Employee::getId);

//Order by employee age
Comparator.comparing(Employee::getDate);

```

#### 1.4 `Collections.thenComparing()`

该工具方法按类别分组。 使用此方法，我们可以链接多个比较器以对多个字段上的对象列表或对象数组进行排序。

它与`SQL GROUP BY`子句非常相似，可以对不同字段上的行进行排序。

```java
//Order by name and then by age
Comparator.comparing(Employee::getName)
			.thenComparing(Employee::getDob);

//Order by name -> date of birth -> id 
Comparator.comparing(Employee::getName)
			.thenComparing(Employee::getDob)
			.thenComparing(Employee::getId);

```

使用以上语法，我们几乎可以创建任何排序逻辑。

#### 1.5 `Collections.reverseOrder()`

此工具方法返回一个比较器，该比较器在实现`Comparable`接口的对象集合上强加*自然排序*或*自定义排序*的逆向。

```java
//Reverse of natural order as specified in 
//Comparable interface's compareTo() method 

Comparator.reversed();

//Reverse of order by name

Comparator.comparing(Employee::getName).reversed();

```

## 2\. Java `Comparator`示例

#### 2.1 排序对象列表

Java 示例**使用比较器按名称**对员工列表进行排序。

```java
ArrayList<Employee> list = new ArrayList<>();

list.add(new Employee(22l, "Lokesh", LocalDate.now()));
list.add(new Employee(30l, "Bob", LocalDate.now()));
list.add(new Employee(18l, "Alex", LocalDate.now()));
list.add(new Employee(5l, "David", LocalDate.now()));
list.add(new Employee(600l, "Charles", LocalDate.now()));

//Sort in reverse natural order
Collections.sort(list, new NameSorter());

System.out.println(list);

```

程序输出。

```java
[
	Employee [id=18, name=Alex, dob=2018-10-30], 
	Employee [id=30, name=Bob, dob=2018-10-30], 
	Employee [id=600, name=Charles, dob=2018-10-30], 
	Employee [id=5, name=David, dob=2018-10-30], 
	Employee [id=22, name=Lokesh, dob=2018-10-30]
]

```

#### 2.2 以相反的顺序对对象列表进行排序

Java 示例**使用**反向顺序**使用比较器按名称**对员工列表进行排序。

```java
ArrayList<Employee> list = new ArrayList<>();

list.add(new Employee(22l, "Lokesh", LocalDate.now()));
list.add(new Employee(30l, "Bob", LocalDate.now()));
list.add(new Employee(18l, "Alex", LocalDate.now()));
list.add(new Employee(5l, "David", LocalDate.now()));
list.add(new Employee(600l, "Charles", LocalDate.now()));

Collections.sort(list, Comparator.comparing( Employee::getName ).reversed());

System.out.println(list);

```

程序输出：

```java
[
	Employee [id=22, name=Lokesh, dob=2018-10-30], 
	Employee [id=5, name=David, dob=2018-10-30], 
	Employee [id=600, name=Charles, dob=2018-10-30], 
	Employee [id=30, name=Bob, dob=2018-10-30], 
	Employee [id=18, name=Alex, dob=2018-10-30]
]

```

#### 2.3 通过按照多个字段对对象列表进行分组排序

Java 示例，用于按多个字段对多个字段（即**字段**）上的雇员列表进行排序。

```java
ArrayList<Employee> list = new ArrayList<>();

list.add(new Employee(22l, "Lokesh", LocalDate.now()));
list.add(new Employee(30l, "Lokesh", LocalDate.now()));
list.add(new Employee(18l, "Alex", LocalDate.now()));
list.add(new Employee(5l, "Lokesh", LocalDate.now()));
list.add(new Employee(600l, "Charles", LocalDate.now()));

Comparator<Employee> groupByComparator = Comparator.comparing(Employee::getName)
                                        .thenComparing(Employee::getDob)
                                        .thenComparing(Employee::getId);

Collections.sort(list, groupByComparator);

System.out.println(list);

```

程序输出：

```java
[
	Employee [id=18, name=Alex, dob=2018-10-30], 
	Employee [id=600, name=Charles, dob=2018-10-30], 
	Employee [id=5, name=Lokesh, dob=2018-10-30], 
	Employee [id=22, name=Lokesh, dob=2018-10-30], 
	Employee [id=30, name=Lokesh, dob=2018-10-30]]

```

## 3\. 总结

在本教程中，我们学习了 Java 集合框架的`Comparator`接口。 它有助于在不更改该类源代码的情况下，对对象施加总体顺序。

我们学会了对对象的列表和数组进行排序。 我们学习了如何使用`Comparator`接口在 Java 中对员工对象进行排序，即 **Java 比较器的多个字段示例**。

将我的问题放在评论部分。

学习愉快！

参考文献：

[`Comparator`接口 Java 文档](https://docs.oracle.com/javase/8/docs/api/java/lang/Comparator.html)