1. 程式人生 > >Java Comparator接口學習筆記

Java Comparator接口學習筆記

print req 依據 sin 例如 cto ret ace 鏈式

Comparator是一個泛型函數式接口T表示待比較對象的類型

@FunctionalInterface
public interface Comparator<T> {
}

1. 抽象方法

唯一的非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

2. 常用靜態/默認方法

① 靜態方法comparing

// 源碼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表達式,該表達式對c1c2提取出來的key進行比較 (用的是c1c2類實現的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);
        }
    }
}

② 靜態方法comparingXXX()

  • 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()

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

Java Comparator接口學習筆記