Guava 强大的 Ordering 排序类
排序器 Ordering
是 Guava流畅风格比较器 Comparator
的实现,它可以用来为构建复杂的比较器,以完成集合排序的功能。
从实现上说,Ordering 实例就是一个特殊的 Comparator 实例。Ordering 把很多基于 Comparator 的静态方法(如 Collections.max
)包装为自己的实例方法(非静态方法),并且提供了链式调用方法,来定制和增强现有的比较器。
1、类声明
以下是 com.google.common.collect.Ordering<T>
类的声明:
@GwtCompatible public final class Preconditions
2、类方法
(1)创建排序器:
常见的排序器可以由下面的静态方法创建
方法 | 描述 |
---|---|
natural() | 对可排序类型做自然排序,如数字按大小,日期按先后排序 |
usingToString() | 按对象的字符串形式做字典排序 [lexicographical ordering] |
from(Comparator) | 把给定的 Comparator 转化为排序器 |
实现自定义的排序器时,除了用上面的 from
方法,也可以跳过实现 Comparator
,直接继承 Ordering
:
Ordering<String> byLengthOrdering = new Ordering<String>() { public int compare(String left, String right) { return Ints.compare(left.length(), right.length()); } };
(2)链式调用方法
通过链式调用,可以由给定的排序器衍生出其它排序器
方法 | 描述 |
---|---|
reverse() | 获取语义相反的排序器 |
nullsFirst() | 使用当前排序器,但额外把 null 值排到最前面。 |
nullsLast() | 使用当前排序器,但额外把 null 值排到最后面。 |
compound(Comparator) | 合成另一个比较器,以处理当前排序器中的相等情况。 |
lexicographical() | 基于处理类型T的排序器,返回该类型的可迭代对象 Iterable<T> 的排序器。 |
onResultOf(Function) | 对集合中元素调用 Function ,再按返回值用当前排序器排序。 |
例如,你需要下面这个类的排序器。
class Foo { @Nullable String sortedBy; int notSortedBy; }
考虑到排序器应该能处理 sortedBy
为 null
的情况,我们可以使用下面的链式调用来合成排序器:
Ordering<Foo> ordering = Ordering.natural().nullsFirst().onResultOf(new Function<Foo, String>() { public String apply(Foo foo) { return foo.sortedBy; } });
当阅读链式调用产生的排序器时,应该从后往前读。
上面的例子中,排序器首先调用 apply
方法获取 sortedBy
值,并把 sortedBy
为 null
的元素都放到最前面,然后把剩下的元素按 sortedBy
进行自然排序。之所以要从后往前读,是因为每次链式调用都是用后面的方法包装了前面的排序器。
注: 用 compound
方法包装排序器时,就不应遵循从后往前读的原则。为了避免理解上的混乱,请不要 compound
写在一长串链式调用的中间,你可以另起一行,在链中最先或最后调用 compound
。
超过一定长度的链式调用,也可能会带来阅读和理解上的难度。我们建议按下面的代码这样,在一个链中最多使用三个方法。此外,你也可以把 Function
分离成中间对象,让链式调用更简洁紧凑。
Ordering<Foo> ordering = Ordering.natural().nullsFirst().onResultOf(sortKeyFunction)
(3)运用排序器
Guava 的排序器实现有若干操纵集合或元素值的方法
方法 | 描述 | 另请参见 |
---|---|---|
greatestOf(Iterable iterable, int k) | 获取可迭代对象中最大的 k 个元素。 | leastOf |
isOrdered(Iterable) | 判断可迭代对象是否已按排序器排序:允许有排序值相等的元素。 | isStrictlyOrdered |
sortedCopy(Iterable) | 判断可迭代对象是否已严格按排序器排序:不允许排序值相等的元素。 | immutableSortedCopy |
min(E, E) | 返回两个参数中最小的那个。如果相等,则返回第一个参数。 | max(E, E) |
min(E, E, E, E...) | 返回多个参数中最小的那个。如果有超过一个参数都最小,则返回第一个最小的参数。 | max(E, E, E, E...) |
min(Iterable) | 返回迭代器中最小的元素。如果可迭代对象中没有元素,则抛出 NoSuchElementException 。 | max(Iterable) , min(Iterator) , max(Iterator) |
(4)所有方法
方法类型 | 方法描述 |
---|---|
static Ordering<Object> | allEqual() 返回一个Ordering,所有值的排序地位都是平等的,表明无排序。 将此排序传递给任何稳定排序算法都不会导致元素顺序发生变化。 |
static Ordering<Object> | arbitrary() 返回所有对象的任意顺序,即compare(a, b) == 0 就是 a == b (identity equality)。 本身的排序是没有任何含义,但是在VM的生命周期是一个常量。 |
int | binarySearch(List<? extends T> sortedList, T key) 已过时,请使用 Collections.binarySearch(List, Object, Comparator) . |
abstract int | compare(T left, T right) 比较两个参数的顺序。 |
<U extends T>Ordering<U> | compound(Comparator<? super U> secondaryComparator) 返回一个Ordering,传入比较器作为第二排序元素。 |
static <T> Ordering<T> | compound(Iterable<? extends Comparator<? super T>> comparators) 返回一个Ordering,会根据传入比较器集合一次比较,直到找到一个非零的结果。 |
static <T> Ordering<T> | explicit(List<T> valuesInOrder) 返回一个Ordering,根据他们出现在给定的列表的顺序比较对象 |
static <T> Ordering<T> | explicit(T leastValue, T... remainingValuesInOrder) 返回一个Ordering,比较对象根据它们的传入的顺序。 |
static <T> Ordering<T> | from(Comparator<T> comparator) 返回一个传入comparator实例的Ordering。 |
static <T> Ordering<T> | from(Ordering<T> ordering) 已过时。 不需要使用它 |
<E extends T> List<E> | greatestOf(Iterable<E> iterable, int k) 根据Ordering对传入iterable由大到小排序,返回前K位的集合。 |
<E extends T> List<E> | greatestOf(Iterator<E> iterator, int k) 根据Ordering对传入iterable由大到小排序,返回前K位的集合。 |
<E extends T>ImmutableList<E> | immutableSortedCopy(Iterable<E> elements) 返回一个不可变的集合,包含根据Ordering对传入元素排序后的所有元素。 |
boolean | isOrdered(Iterable<? extends T> iterable) 根据Ordering对传入iterable元素迭代,如果下一个元素大于或等于上一个元素,返回true。 |
boolean | isStrictlyOrdered(Iterable<? extends T> iterable) 根据Ordering对传入iterable元素迭代,如果下一个元素严格大于上一个元素,返回true。 |
<E extends T> List<E> | leastOf(Iterable<E> iterable, int k) 根据Ordering对传入iterable由小到大排序,返回前K位的集合。 |
<E extends T> List<E> | leastOf(Iterator<E> iterator, int k) 根据Ordering对传入iterable由小到大排序,返回前K位的集合。 |
<S extends T>Ordering<Iterable<S>> | lexicographical() 返回一个新的Ordering,通过相应的元素两两迭代,直到找到一个非零的结果。强加“字典顺序”。 |
<E extends T> E | max(E a, E b) 根据Ordering返回传入参数的最大值。 |
<E extends T> E | max(E a, E b, E c, E... rest) 根据Ordering返回传入参数的最大值。 |
<E extends T> E | max(Iterable<E> iterable) 根据Ordering返回传入参数的最大值。 |
<E extends T> E | max(Iterator<E> iterator) 根据Ordering返回传入参数的最大值。 |
<E extends T> E | min(E a, E b) 根据Ordering返回传入参数的最小值。 |
<E extends T> E | min(E a, E b, E c, E... rest) 根据Ordering返回传入参数的最小值。 |
<E extends T> E | min(Iterable<E> iterable) 根据Ordering返回传入参数的最小值。 |
E<E extends T> E | min(Iterator<E> iterator) 根据Ordering返回传入参数的最小值。 |
static <C extendsComparable> Ordering<C> | natural() 对可排序类型做自然排序,如数字按大小,日期按先后排序 |
<S extends T>Ordering<S> | nullsFirst() 根据Ordering排序,null值放在最前面,并使用它来比较非空值。 |
<S extends T>Ordering<S> | nullsLast() 根据Ordering排序,null值放在最后面,并使用此排序来比较非空值。 |
<F> Ordering<F> | onResultOf(Function<F,? extends T> function) 将传入function应用到每个元素上面,再通过Ordering进行排序。 |
<S extends T>Ordering<S> | reverse() 返回与当前Ordering相反的排序。相当于 Collections.reverseOrder(Comparator) 。 |
<E extends T> List<E> | sortedCopy(Iterable<E> elements) 返回一个可变的集合,包含根据Ordering对传入元素排序后的所有元素。 |
static Ordering<Object> | usingToString() 根据toString返回的字符串按照字典顺序排序。 |
三、Ordering 示例
接下来,我们就通过代码实例来进行 Guava Ordering 的学习,由于 Guava Ordering 中涉及的排序方法较多,一些方法还不是很理解,下面只对方法进行简单的示例,以后随着学习的深入会继续完善和补充此示例,
代码如下:
package com.example.guava.base; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; import com.google.common.primitives.Doubles; import junit.framework.TestCase; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.*; import static com.google.common.truth.Truth.assertThat; import static java.util.Arrays.asList; /** * 排序 */ public class OrderingTests extends TestCase { /** * 1、allEqual 允许有null */ public void testAllEqual() { Ordering<Object> comparator = Ordering.allEqual(); assertSame(comparator, comparator.reverse()); assertEquals(0, comparator.compare(null, null)); assertEquals(0, comparator.compare(new Object(), new Object())); assertEquals(0, comparator.compare("apples", "oranges")); assertEquals("Ordering.allEqual()", comparator.toString()); List<String> strings = ImmutableList.of("b", "a", "d", "c"); assertEquals(strings, comparator.sortedCopy(strings)); assertEquals(strings, comparator.immutableSortedCopy(strings)); } /** * 2、natural 不能有null */ public void testNatural() { Ordering<Integer> comparator = Ordering.natural(); try { comparator.compare(1, null); fail(); } catch (NullPointerException expected) { } try { comparator.compare(null, 2); fail(); } catch (NullPointerException expected) { } try { comparator.compare(null, null); fail(); } catch (NullPointerException expected) { } assertEquals("Ordering.natural()", comparator.toString()); } /** * 3、List集合 复杂排序示例 */ public void testComplicatedOrderingExample() { Ordering<Iterable<Integer>> example = Ordering.<Integer>natural().nullsFirst().reverse().lexicographical().reverse().nullsLast(); List<Integer> list1 = Lists.newArrayList(); List<Integer> list2 = Lists.newArrayList(1); List<Integer> list3 = Lists.newArrayList(1, 1); List<Integer> list4 = Lists.newArrayList(1, 2); List<Integer> list5 = Lists.newArrayList(1, null, 2); List<Integer> list6 = Lists.newArrayList(2); Integer nullInt = null; List<Integer> list7 = Lists.newArrayList(nullInt); List<Integer> list8 = Lists.newArrayList(nullInt, nullInt); List<List<Integer>> list = Lists.newArrayList(list1, list2, list3, list4, list5, list6, list7, list8, null); List<List<Integer>> sorted = example.sortedCopy(list); /** * [null, null] * [null] * [1, null, 2] * [1, 1] * [1, 2] * [1] * [2] * [] * null */ sorted.forEach(System.out::println); // [[null, null], [null], [1, null, 2], [1, 1], [1, 2], [1], [2], [], null] assertThat(sorted) .containsExactly( Lists.newArrayList(nullInt, nullInt), Lists.newArrayList(nullInt), Lists.newArrayList(1, null, 2), Lists.newArrayList(1, 1), Lists.newArrayList(1, 2), Lists.newArrayList(1), Lists.newArrayList(2), Lists.newArrayList(), null) .inOrder(); } /** * 4、from 把给定的 Comparator 转化为排序器 */ public void testFrom() { // String.CASE_INSENSITIVE_ORDER 按照 ASCII 排序 Ordering<String> caseInsensitiveOrdering = Ordering.from(String.CASE_INSENSITIVE_ORDER); assertTrue(caseInsensitiveOrdering.compare("A", "a") == 0); assertTrue(caseInsensitiveOrdering.compare("a", "B") < 0); assertTrue(caseInsensitiveOrdering.compare("B", "a") > 0); ArrayList<String> list = Lists.newArrayList("tingfeng", "abcdef", "ABCDEF", "rapido", "chengxumiao"); List<String> sortedCopy = caseInsensitiveOrdering.sortedCopy(list); sortedCopy.forEach(System.out::println); } /* * 5、explicit(ExplicitOrdering)返回一个Ordering,根据它们的传入的顺序比较对象。只能比较参数列表中存在的对象 */ public void testExplicit_none() { Comparator<Integer> c = Ordering.explicit(Collections.emptyList()); try { c.compare(0, 0); } catch (Exception e) { // e.printStackTrace(); } assertEquals("Ordering.explicit([])", c.toString()); } public void testExplicit_one() { Comparator<Integer> c = Ordering.explicit(0); assertEquals(0, c.compare(0, 0)); try { c.compare(0, 1); fail(); } catch (Exception e) { // e.printStackTrace(); } assertEquals("Ordering.explicit([0])", c.toString()); } public void testExplicit_two() { // Comparator<Integer> c = Ordering.explicit(42, 5); // assertEquals(0, c.compare(5, 5)); // assertTrue(c.compare(5, 42) > 0); // assertTrue(c.compare(42, 5) < 0); Comparator<Integer> c = Ordering.explicit(5, 10); assertEquals(0, c.compare(5, 5)); assertTrue(c.compare(5, 10) < 0); assertTrue(c.compare(10, 5) > 0); try { c.compare(5, 666); fail(); } catch (Exception e) { // e.printStackTrace(); } } public void testExplicit_three() { // explicit:根据传入对象的顺序排序 Double first = 0.1; Double[] second = {0.2, 0.3, 0.5}; List<Double> numbers = Lists.asList(first, second); //排序比较器:根据原始的大小排序 Ordering<Double> peopleOrdering = new Ordering<Double>() { @Override public int compare(Double left, Double right) { return Doubles.compare(left, right); } }; peopleOrdering.reverse().explicit(numbers).sortedCopy(numbers).forEach(System.out::println);//[0.1, 0.2, 0.3, 0.5] } public void testExplicit_sortingExample() { Comparator<Integer> c = Ordering.explicit(2, 8, 6, 1, 7, 5, 3, 4, 0, 9); List<Integer> list = Arrays.asList(0, 3, 5, 6, 7, 8, 9); Collections.sort(list, c); // 8, 6, 7, 5, 3, 0, 9 list.forEach(System.out::println); assertThat(list).containsExactly(8, 6, 7, 5, 3, 0, 9).inOrder(); } /** * key重复异常 */ public void testExplicit_withDuplicates() { try { Ordering.explicit(1, 2, 3, 4, 2); fail(); } catch (IllegalArgumentException expected) { expected.printStackTrace(); } } /** * 6、arbitrary 返回所有对象的任意顺序 */ public void testArbitrary_withoutCollisions() { List<Integer> list = Lists.newArrayList(); for (int i = 0; i < 50; i++) { list.add(i); } Ordering<Object> arbitrary = Ordering.arbitrary(); Collections.sort(list, arbitrary); list.forEach(System.out::println); assertEquals("Ordering.arbitrary()", arbitrary.toString()); } /** * 7、usingToString */ public void testUsingToString() { Ordering<Object> ordering = Ordering.usingToString(); assertEquals("Ordering.usingToString()", ordering.toString()); List<String> list = Lists.newArrayList("peida", "jerry", "harry", "eva", "jhon", "neron"); System.out.println("list:" + list); // 使用Comparable类型的自然顺序, 例如:整数从小到大,字符串是按字典顺序; Ordering<String> naturalOrdering = Ordering.natural(); // 使用toString()返回的字符串按字典顺序进行排序; Ordering<Object> usingToStringOrdering = Ordering.usingToString(); // 返回一个所有对象的任意顺序 Ordering<Object> arbitraryOrdering = Ordering.arbitrary(); System.out.println("naturalOrdering:" + naturalOrdering.sortedCopy(list)); System.out.println("usingToStringOrdering:" + usingToStringOrdering.sortedCopy(list)); System.out.println("arbitraryOrdering:" + arbitraryOrdering.sortedCopy(list)); } /** * 8、reverse 取返 */ public void testReverse() { List<String> list = Lists.newArrayList("peida", "jerry", "harry", "eva", "jhon", "neron"); Collections.sort(list, Ordering.natural().reverse()); list.forEach(System.out::println); } private enum StringLengthFunction implements Function<String, Integer> { StringLength; @Override public Integer apply(String string) { return string.length(); } } /** * 9、onResultOf 将传入function应用到每个元素上面,再通过Ordering进行排序。 */ public void testOnResultOf_1() { // 外部枚举函数 Ordering<String> ordering = Ordering.natural().onResultOf(StringLengthFunction.StringLength); assertTrue(ordering.compare("to", "be") == 0); assertTrue(ordering.compare("or", "not") < 0); assertTrue(ordering.compare("that", "to") > 0); assertEquals("Ordering.natural().onResultOf(StringLength)", ordering.toString()); ArrayList<String> list = Lists.newArrayList("tingfeng", "abcds", "ABCDEF", "rapido", "chengxumiao"); ordering.sortedCopy(list).forEach(System.out::println); } public void testOnResultOf_2() { // 匿名内部类函数 Ordering<String> ordering = Ordering.natural().onResultOf(new Function<String, Comparable>() { @Override public Comparable apply(@Nullable String input) { return input.length(); } }); ArrayList<String> list = Lists.newArrayList("tingfeng", "abcds", "ABCDEF", "rapido", "chengxumiao"); ordering.sortedCopy(list).forEach(System.out::println); } public void testOnResultOf_3() { // lambda 表达式函数 Ordering<String> ordering = Ordering.natural().reverse().onResultOf(str -> str.length()); ArrayList<String> list = Lists.newArrayList("tingfeng", "abcds", "ABCDEF", "rapido", "chengxumiao"); ordering.sortedCopy(list).forEach(System.out::println); } /** * 10、nullsFirst */ public void testNullsFirst_NullsLast() { ArrayList<String> list = Lists.newArrayList("tingfeng", null, "abcds", "ABCDEF", null, "rapido", "chengxumiao"); Collections.sort(list, Ordering.natural().nullsFirst()); list.forEach(System.out::println); Ordering.natural().nullsLast().sortedCopy(list).forEach(System.out::println); } /** * 11、NullsLast */ public void testNullsLast() { ArrayList<String> list = Lists.newArrayList("tingfeng", null, "abcds", "ABCDEF", null, "rapido", "chengxumiao"); Ordering.natural().nullsLast().sortedCopy(list).forEach(System.out::println); } /** * 12、isOrdered 下一个元素大于或等于上一个元素,返回true */ public void testIsOrdered() { Ordering<Comparable> ordering = Ordering.natural(); assertFalse(ordering.isOrdered(asList(5, 3, 0, 9))); assertFalse(ordering.isOrdered(asList(0, 5, 3, 9))); assertTrue(ordering.isOrdered(asList(0, 3, 5, 9))); assertTrue(ordering.isOrdered(asList(0, 0, 3, 3))); assertTrue(ordering.isOrdered(asList(0, 3))); assertTrue(ordering.isOrdered(Collections.singleton(1))); assertTrue(ordering.isOrdered(Collections.<Integer>emptyList())); } /** * 13、isStrictlyOrdered 下一个元素大于上一个元素,返回true */ public void testIsStrictlyOrdered() { Ordering<Comparable> ordering = Ordering.natural(); assertFalse(ordering.isStrictlyOrdered(asList(5, 3, 0, 9))); assertFalse(ordering.isStrictlyOrdered(asList(0, 5, 3, 9))); assertFalse(ordering.isStrictlyOrdered(asList(0, 0, 3, 3))); assertTrue(ordering.isStrictlyOrdered(asList(0, 3, 5, 9))); assertTrue(ordering.isStrictlyOrdered(asList(0, 3))); assertTrue(ordering.isStrictlyOrdered(Collections.singleton(1))); assertTrue(ordering.isStrictlyOrdered(Collections.<Integer>emptyList())); } /** * 判断集合是否只读 */ private static void assertListImmutable(List<Integer> result) { try { result.set(0, 1); fail(); } catch (UnsupportedOperationException expected) { // pass } } /** * 14、leastOf 有点类似截取集合前几位的概念 */ public void testLeastOfIterable_simple_1() { List<Integer> result = Ordering.natural().leastOf(Arrays.asList(3, 4, 5, -1), 2); assertTrue(result instanceof RandomAccess); assertListImmutable(result); assertEquals(ImmutableList.of(-1, 3), result); } public void testLeastOfIterator_simple_1() { List<Integer> result = Ordering.natural().leastOf(Iterators.forArray(3, 4, 5, -1), 2); assertTrue(result instanceof RandomAccess); assertListImmutable(result); assertEquals(ImmutableList.of(-1, 3), result); } public void testLeastOfIterable_simple_nMinusOne_withNullElement() { List<Integer> list = Arrays.asList(3, null, 5, -1); List<Integer> result = Ordering.natural().nullsLast().leastOf(list, list.size() - 1); assertTrue(result instanceof RandomAccess); assertListImmutable(result); assertEquals(ImmutableList.of(-1, 3, 5), result); } /** * 15、min 和 max */ public void testIteratorMinAndMax() { Ordering<Comparable> ordering = Ordering.natural(); List<Integer> ints = Lists.newArrayList(5, 3, 0, 9); assertEquals(9, (int) ordering.max(ints)); assertEquals(0, (int) ordering.min(ints)); assertEquals(9, (int) ordering.max(ints.iterator())); assertEquals(0, (int) ordering.min(ints.iterator())); assertEquals(9, (int) ordering.max(ints.listIterator())); assertEquals(0, (int) ordering.min(ints.listIterator())); // 当值相同时,返回第一个参数,此处a正确,b就不正确 Integer a = new Integer(4); Integer b = new Integer(4); ints = Lists.newArrayList(a, b, b); assertSame(a, ordering.max(ints.iterator())); assertSame(a, ordering.min(ints.iterator())); } public void testIteratorMinExhaustsIterator() { List<Integer> ints = Lists.newArrayList(9, 0, 3, 5); Iterator<Integer> iterator = ints.iterator(); assertEquals(0, (int) Ordering.natural().min(iterator)); assertFalse(iterator.hasNext()); } public void testIteratorMaxExhaustsIterator() { List<Integer> ints = Lists.newArrayList(9, 0, 3, 5); Iterator<Integer> iterator = ints.iterator(); assertEquals(9, (int) Ordering.natural().max(iterator)); assertFalse(iterator.hasNext()); } }
四、相关文章
未经允许请勿转载:程序喵 » Google Guava 快速入门 —— 【基础】强大的 Ordering 排序类