1. 概述

在这篇文章中,我们将探讨Guava库中的Ordering类。

Ordering类实现了Comparator接口,并为我们提供了创建和链式组合比较器的有用 fluent API。

顺便提一下,值得了解一下Java新引入的Comparator.comparing()方法——它提供了类似的功能;这里有一个使用该API的实用示例:Java 8 排序 lambda

2. 创建Ordering

Ordering类提供了一个有用的构建器方法,返回一个可用于在集合的sort()方法或其他需要Comparator实例的地方使用的适当实例。

我们可以通过调用natural()方法来创建自然顺序的实例:

List<Integer> integers = Arrays.asList(3, 2, 1);

integers.sort(Ordering.natural());

assertEquals(Arrays.asList(1,2,3), integers);

假设我们有一个Person对象的集合:

class Person {
    private String name;
    private Integer age;
    
    // standard constructors, getters
}

如果我们想按age字段对这样的对象列表进行排序,可以通过扩展它来创建自定义的Ordering

List<Person> persons = Arrays.asList(new Person("Michael", 10), new Person("Alice", 3));
Ordering<Person> orderingByAge = new Ordering<Person>() {
    @Override
    public int compare(Person p1, Person p2) {
        return Ints.compare(p1.age, p2.age);
    }
};

persons.sort(orderingByAge);

assertEquals(Arrays.asList(new Person("Alice", 3), new Person("Michael", 10)), persons);

然后我们可以使用orderingByAge并将其传递给sort()方法。

3. 链接Orderings

这个类的一个有用特性是我们可以链式地应用不同的排序方式。例如,我们有一个Person对象的集合,想要按age字段排序,并且将age字段为null的对象放在列表的开头:

List<Person> persons = Arrays.asList(
  new Person("Michael", 10),
  new Person("Alice", 3), 
  new Person("Thomas", null));
 
Ordering<Person> ordering = Ordering
  .natural()
  .nullsFirst()
  .onResultOf(new Function<Person, Comparable>() {
      @Override
      public Comparable apply(Person person) {
          return person.age;
      }
});

persons.sort(ordering);
        
assertEquals(Arrays.asList(
  new Person("Thomas", null), 
  new Person("Alice", 3), 
  new Person("Michael", 10)), persons);

这里需要注意的是特定Ordering执行的顺序——从右到左。首先,onResultOf()方法被执行,该方法提取我们想要比较的字段。

接着,nullFirst()比较器被应用。因此,排序后的集合将把age字段为nullPerson对象放在列表的开头。

排序过程的最后,使用natural()方法指定的自然顺序来比较age字段。

4. 总结

在这篇文章中,我们研究了Guava库中的Ordering类,它使我们能够创建更流畅、优雅的Comparator。我们创建了自定义的Ordering,使用了API中预定义的,还通过链式操作以实现更定制的排序。

所有这些示例和代码片段的实现可以在GitHub项目中找到——这是一个基于Maven的项目,可以直接导入并运行,无需额外配置。


» 下一篇: ConcurrentMap 介绍