1. 引言

本指南展示 如何使用 Guava 风格的 Ordering 和 Comparator。延续之前 Guava 集合实用指南 的形式,聚焦于实际场景的代码示例。

2. 实用指南

2.1 处理集合中的 null 值

2.1.1 null 值排在最前

List<Integer> toSort = Arrays.asList(3, 5, 4, null, 1, 2);
Collections.sort(toSort, Ordering.natural().nullsFirst());
assertThat(toSort.get(0), nullValue());

2.1.2 null 值排在最后

List<Integer> toSort = Arrays.asList(3, 5, 4, null, 1, 2);
Collections.sort(toSort, Ordering.natural().nullsLast());
assertThat(toSort.get(toSort.size() - 1), nullValue());

2.2 自然排序

List<Integer> toSort = Arrays.asList(3, 5, 4, 1, 2);
Collections.sort(toSort, Ordering.natural());

assertTrue(Ordering.natural().isOrdered(toSort));

2.3 链式排序(组合两个排序规则)

List<Integer> toSort = Arrays.asList(3, 5, 4, 1, 2);
Collections.sort(toSort, Ordering.natural().reverse());

2.4 反转排序

List<Integer> toSort = Arrays.asList(3, 5, 4, null, 1, 2);
Collections.sort(toSort, Ordering.natural().nullsLast().reverse());
assertThat(toSort.get(0), nullValue());

2.5 自定义排序——按字符串长度

private class OrderingByLenght extends Ordering<String> {
    @Override
    public int compare(String s1, String s2) {
        return Ints.compare(s1.length(), s2.length());
    }
}
List<String> toSort = Arrays.asList("zz", "aa", "b", "ccc");
Ordering<String> byLength = new OrderingByLenght();
Collections.sort(toSort, byLength);

Ordering<String> expectedOrder = Ordering.explicit(Lists.newArrayList("b", "zz", "aa", "ccc"));
assertTrue(expectedOrder.isOrdered(toSort))

2.6 检查显式顺序

List<String> toSort = Arrays.asList("zz", "aa", "b", "ccc");
Ordering<String> byLength = new OrderingByLenght();
Collections.sort(toSort, byLength);

Ordering<String> expectedOrder = Ordering.explicit(Lists.newArrayList("b", "zz", "aa", "ccc"));
assertTrue(expectedOrder.isOrdered(toSort));

2.7 检查严格排序

List<Integer> toSort = Arrays.asList(3, 5, 4, 2, 1, 2);
Collections.sort(toSort, Ordering.natural());

assertFalse(Ordering.natural().isStrictlyOrdered(toSort));

2.8 二级排序

List<String> toSort = Arrays.asList("zz", "aa", "b", "ccc");
Ordering<String> byLength = new OrderingByLenght();
Collections.sort(toSort, byLength.compound(Ordering.natural()));

Ordering<String> expectedOrder = Ordering.explicit(Lists.newArrayList("b", "aa", "zz", "ccc"));
assertTrue(expectedOrder.isOrdered(toSort));

2.9 复杂自定义排序示例——链式调用

List<String> toSort = Arrays.asList("zz", "aa", null, "b", "ccc");
Collections.sort(toSort, 
    new OrderingByLenght().reverse().compound(Ordering.natural()).nullsLast());
System.out.println(toSort);

2.10 使用 toString() 表示进行排序

List<Integer> toSort = Arrays.asList(1, 2, 11);
Collections.sort(toSort, Ordering.usingToString());

Ordering<Integer> expectedOrder = Ordering.explicit(Lists.newArrayList(1, 11, 2));
assertTrue(expectedOrder.isOrdered(toSort));

2.11 排序后查找(二分查找)

List<Integer> toSort = Arrays.asList(1, 2, 11);
Collections.sort(toSort, Ordering.usingToString());
int found = Ordering.usingToString().binarySearch(toSort, 2);
System.out.println(found);

2.12 无需排序直接查找最小/最大值(更快)

List<Integer> toSort = Arrays.asList(2, 1, 11, 100, 8, 14);
int found = Ordering.usingToString().min(toSort);
assertThat(found, equalTo(1));

2.13 根据排序规则创建排序后的列表副本

List<String> toSort = Arrays.asList("aa", "b", "ccc");
List<String> sortedCopy = new OrderingByLenght().sortedCopy(toSort);

Ordering<String> expectedOrder = Ordering.explicit(Lists.newArrayList("b", "aa", "ccc"));
assertFalse(expectedOrder.isOrdered(toSort));
assertTrue(expectedOrder.isOrdered(sortedCopy));

2.14 创建排序的部分副本——最小的几个元素

List<Integer> toSort = Arrays.asList(2, 1, 11, 100, 8, 14);
List<Integer> leastOf = Ordering.natural().leastOf(toSort, 3);
List<Integer> expected = Lists.newArrayList(1, 2, 8);
assertThat(expected, equalTo(leastOf));

2.15 通过中间函数进行排序

List<Integer> toSort = Arrays.asList(2, 1, 11, 100, 8, 14);
Ordering<Object> ordering = Ordering.natural().onResultOf(Functions.toStringFunction());
List<Integer> sortedCopy = ordering.sortedCopy(toSort);

List<Integer> expected = Lists.newArrayList(1, 100, 11, 14, 2, 8);
assertThat(expected, equalTo(sortedCopy));

⚠️ 注意:排序逻辑会先将数字通过函数转换为字符串,再按字符串自然序排序

3. 更多 Guava 实用指南

Guava 是一个功能全面且极其实用的库——以下是其他以实用指南形式覆盖的 API:

4. 总结

这种实验性格式——实用指南——聚焦于简洁和高效,因此大多数示例除了代码本身没有额外解释

如前所述,这是一份持续更新的文档——欢迎在评论中提供新示例和用例,我也会不断补充自己遇到的新场景。

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


原始标题:Guava Ordering Cookbook

« 上一篇: Guava集合编程手册