Comparator
是一个泛型函数式接口,T
表示待比较对象的类型:
@FunctionalInterface public interface Comparator<T> { }
唯一的非Object抽象方法: compare
int compare(T o1, T o2)
根据o1, o2的大小关系返回:负数、0、正数
其比较逻辑依赖于赋值给Comparator
类型变量的Lambda表达式、Comparator
对象等:
Comparator<String> comparator = Comparator.comparingInt(String::length); // 比较String类对象的length System.out.println(comparator.compare("Tom", "Jerry")); // -1
// 源码1 public static <T, U extends Comparable<? super U>> Comparator<T> comparing( Function<? super T, ? extends U> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); }
返回值:
comparing
返回一个T
类型的Comparator
对象(也就是用于比较T
类型对象的Comparator
)参数:
comparing
的参数是一个Function
类型,它接收T
类型及T
的超类型, 返回U
类型及U
的子类型。keyExtractor
用Lambda表达式实现例如,输入
String
,提取其长度:Comparator<String> keyComparator = Comparator.comparing(String::length); keyComparator.compare("Tom", "Jerry");
- 函数体:
- 首先,确保
keyExtractor
不是null
- 然后,返回一个Lambda表达式,该表达式对
c1
和c2
提取出来的key
进行比较 (用的是c1
和c2
类实现的compareTo()
进行比较)
- 首先,确保
public static <T, U> Comparator<T> comparing( Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) { Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyComparator); return (Comparator<T> & Serializable) (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2)); }
与上面类似,只不过将key
的比较逻辑由compareTo()
替换成了自定义的比较逻辑
实例:
package Lambda.ComparatorDemo; import java.util.Arrays; import java.util.Comparator; class Person { private String fname; private String lname; public Person(String fname, String lname) { this.fname = fname; this.lname = lname; } public String getFname() { return fname; } public String getLname() { return lname; } @Override public String toString() { return fname + " " + lname; } } public class ComparingDemo { public static void main(String[] args) { Person p1 = new Person("Tom", "Kenn"); Person p2 = new Person("Alice", "Zed"); Person[] persons1 = {p1, p2}; Person[] persons2 = persons1.clone(); // 依据First Name排序(用的是String类的compareTo的比较逻辑) Arrays.sort(persons1, Comparator.comparing(Person::getFname)); System.out.println("Person1 (Sorted by first name): "); for (Person p : persons1) { System.out.println(p); } System.out.println(); // 依据First Name的长度排序 Arrays.sort(persons2, Comparator.comparing(Person::getFname, Comparator.comparingInt(String::length))); System.out.println("Person2 (Sorted by length of first name):"); for (Person p : persons2) { System.out.println(p); } } }
comparingInt()
comparingDouble()
comparingLong()
与comparing
是一样的思路,只不过comparingXXX()
将comparing
中的提取出来的key
类型固定为了XXX
:
public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); }
thenComparing
是默认方法,需要对具体的Comparator
对象调用,它用于将多个Comparator
结合起来实现“链式的比较”:先根据XXX比较,再根据XXX比较,...
// 源码 default Comparator<T> thenComparing(Comparator<? super T> other) { Objects.requireNonNull(other); return (Comparator<T> & Serializable) (c1, c2) -> { int res = compare(c1, c2); return (res != 0) ? res : other.compare(c1, c2); }; }
public class thenComparingDemo { public static void main(String[] args) { Person p1 = new Person("Alice", "Jessy"); Person p2 = new Person("Alice", "Ann"); Person p3 = new Person("Tom", "Smith"); Person[] persons = {p1, p2, p3}; // 先根据first name比较,再根据last name的长度比较 Comparator<Person> chainedComparator = Comparator.comparing(Person::getFname) .thenComparing((x, y) -> (x.getLname().length() - y.getLname().length())); // 先根据first name排序,再根据last name的长度排序 Arrays.sort(persons, chainedComparator); for (Person p : persons) { System.out.println(p); } } } /* Alice Ann Alice Jessy Tom Smith
参考:
https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#thenComparing-java.util.Comparator