Panduan untuk Java 8 Comparator.comparing ()

1. Gambaran keseluruhan

Java 8 memperkenalkan beberapa peningkatan pada antara muka Perbandingan , termasuk segelintir fungsi statis yang sangat berguna ketika datang dengan urutan koleksi.

Java 8 lambdas dapat dimanfaatkan dengan berkesan dengan antara muka Perbandingan juga. Penjelasan terperinci mengenai lambdas dan Comparator boleh didapati di sini, dan catatan mengenai penyortiran dan aplikasi Comparator boleh didapati di sini.

Dalam tutorial ini, kita akan meneroka beberapa fungsi yang diperkenalkan untuk antara muka Perbandingan di Java 8 .

2. Bermula

2.1. Contoh Kelas Kacang

Untuk contoh dalam artikel ini, mari buat kacang Karyawan dan gunakan bidangnya untuk tujuan membandingkan dan menyusun:

public class Employee { String name; int age; double salary; long mobile; // constructors, getters & setters }

2.2. Data Ujian Kami

Mari juga buat barisan pekerja yang akan digunakan untuk menyimpan hasil jenis kami dalam pelbagai kes ujian sepanjang artikel:

employees = new Employee[] { ... };

Susunan awal elemen pekerja adalah:

[Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

Sepanjang artikel, kami akan menyusun di atas array Karyawan menggunakan fungsi yang berbeza.

Untuk penegasan ujian, kami akan menggunakan satu set tatasusunan pra-disusun yang akan kami bandingkan dengan hasil urutan kami (iaitu, susunan pekerja ) untuk senario yang berbeza.

Mari nyatakan beberapa susunan berikut:

@Before public void initData() { sortedEmployeesByName = new Employee[] {...}; sortedEmployeesByNameDesc = new Employee[] {...}; sortedEmployeesByAge = new Employee[] {...}; // ... }

Seperti biasa, sila rujuk pautan GitHub kami untuk mendapatkan kod yang lengkap.

3. Menggunakan Comparator.comparing

Bahagian ini merangkumi varian fungsi statik Comparator.comparing .

3.1. Varian Pemilih Utama

The Comparator.comparing fungsi statik menerima semacam kunci Fungsi dan mengembalikan Comparator untuk jenis yang mengandungi kunci jenis yang:

static 
    
      Comparator comparing( Function keyExtractor)
    

Untuk melihat ini dalam tindakan, mari gunakan bidang nama di Karyawan sebagai kunci sort dan lulus rujukan kaedahnya sebagai argumen jenis Fungsi. The Comparator pulang dari IS yang sama yang digunakan untuk menyusun:

@Test public void whenComparing_thenSortedByName() { Comparator employeeNameComparator = Comparator.comparing(Employee::getName); Arrays.sort(employees, employeeNameComparator); assertTrue(Arrays.equals(employees, sortedEmployeesByName)); }

Seperti yang anda lihat, nilai susunan pekerja disusun berdasarkan nama sebagai hasil dari jenis:

[Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)] 

3.2. Varian Pemilih dan Pembanding Utama

Terdapat pilihan lain yang memudahkan untuk mengatasi urutan semula jadi kunci pengisihan dengan menyediakan Pembanding yang membuat pesanan khusus untuk kunci urut:

static  Comparator comparing( Function keyExtractor, Comparator keyComparator)

Mari kita mengubah suai ujian di atas, yang mengatasi perintah itu semula jadi mengisih mengikut nama medan dengan menyediakan Comparator untuk menyusun nama-nama dalam urutan sebagai hujah kedua untuk Comparator.comparing :

@Test public void whenComparingWithComparator_thenSortedByNameDesc() { Comparator employeeNameComparator = Comparator.comparing( Employee::getName, (s1, s2) -> { return s2.compareTo(s1); }); Arrays.sort(employees, employeeNameComparator); assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc)); }

Seperti yang anda lihat, hasilnya disusun mengikut turutan mengikut nama :

[Employee(name=Keith, age=35, salary=4000.0, mobile=3924401), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Ace, age=22, salary=2000.0, mobile=5924001)]

3.3. Menggunakan Comparator.reversed

Apabila dipanggil pada Comparator yang ada , kaedah instance Comparator.reversed mengembalikan Comparator baru yang membalikkan susunan urutan asal.

Mari gunakan Comparator yang menyusun pekerja mengikut nama dan membalikkannya supaya pekerja disusun mengikut urutan nama :

@Test public void whenReversed_thenSortedByNameDesc() { Comparator employeeNameComparator = Comparator.comparing(Employee::getName); Comparator employeeNameComparatorReversed = employeeNameComparator.reversed(); Arrays.sort(employees, employeeNameComparatorReversed); assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc)); }

Hasilnya disusun mengikut turutan mengikut nama :

[Employee(name=Keith, age=35, salary=4000.0, mobile=3924401), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Ace, age=22, salary=2000.0, mobile=5924001)]

3.4. Menggunakan Comparator.comparingInt

Terdapat juga fungsi Comparator.comparingInt yang melakukan perkara yang sama seperti Comparator.comparing , tetapi ia hanya mengambil masa int pemilih. Mari cuba dengan contoh di mana kita memesan pekerja mengikut usia :

@Test public void whenComparingInt_thenSortedByAge() { Comparator employeeAgeComparator = Comparator.comparingInt(Employee::getAge); Arrays.sort(employees, employeeAgeComparator); assertTrue(Arrays.equals(employees, sortedEmployeesByAge)); }

Mari lihat bagaimana nilai susunan pekerja disusun mengikut urutan:

[Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

3.5. Menggunakan Comparator.comparingLong

Sama dengan apa yang kita lakukan untuk int kunci, mari kita lihat contoh menggunakan Comparator.comparingLong untuk mempertimbangkan kunci jenis jenis lama dengan mengarahkan pekerja mudah oleh mudah alih bidang:

@Test public void whenComparingLong_thenSortedByMobile() { Comparator employeeMobileComparator = Comparator.comparingLong(Employee::getMobile); Arrays.sort(employees, employeeMobileComparator); assertTrue(Arrays.equals(employees, sortedEmployeesByMobile)); }

Let's see how the employees array values are ordered after the sort with mobile as the key:

[Employee(name=Keith, age=35, salary=4000.0, mobile=3924401), Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), Employee(name=John, age=25, salary=3000.0, mobile=9922001)]

3.6. Using Comparator.comparingDouble

Again, similar to what we did for int and long keys, let's see an example using Comparator.comparingDouble to consider a sort key of type double by ordering the employees array by the salary field:

@Test public void whenComparingDouble_thenSortedBySalary() { Comparator employeeSalaryComparator = Comparator.comparingDouble(Employee::getSalary); Arrays.sort(employees, employeeSalaryComparator); assertTrue(Arrays.equals(employees, sortedEmployeesBySalary)); }

Let's see how the employees array values are ordered after the sort with salary as the sort key:

[Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

4. Considering Natural Order in Comparator

The natural order is defined by the behavior of the Comparable interface implementation. More information about the difference between Comparator and uses of the Comparable interface can be found in this article.

Let's implement Comparable in our Employee class so that we can try the naturalOrder and reverseOrder functions of the Comparator interface:

public class Employee implements Comparable{ // ... @Override public int compareTo(Employee argEmployee) { return name.compareTo(argEmployee.getName()); } }

4.1. Using Natural Order

The naturalOrder function returns the Comparator for the return type mentioned in the signature:

static 
    
      Comparator naturalOrder()
    

Given the above logic to compare employees based on name field, let's use this function to obtain to a Comparator which sorts the employees array in natural order:

@Test public void whenNaturalOrder_thenSortedByName() { Comparator employeeNameComparator = Comparator. naturalOrder(); Arrays.sort(employees, employeeNameComparator); assertTrue(Arrays.equals(employees, sortedEmployeesByName)); }

Let's see how the employees array values are ordered after the sort:

[Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

4.2. Using Reverse Natural Order

Similar to naturalOrder, let's use the reverseOrder method to generate a Comparator which will produce a reverse ordering of employees to the one in the naturalOrder example:

@Test public void whenReverseOrder_thenSortedByNameDesc() { Comparator employeeNameComparator = Comparator. reverseOrder(); Arrays.sort(employees, employeeNameComparator); assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc)); }

Let's see how the employees array values are ordered after the sort:

[Employee(name=Keith, age=35, salary=4000.0, mobile=3924401), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Ace, age=22, salary=2000.0, mobile=5924001)]

5. Considering Null Values in Comparator

This section covers functions nullsFirst and nullsLast, which consider null values in ordering and keep the null values at the beginning or end of the ordering sequence.

5.1. Considering Null First

Let's randomly insert null values in employees array:

[Employee(name=John, age=25, salary=3000.0, mobile=9922001), null, Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), null, Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

The nullsFirst function will return a Comparator that keeps all nulls at the beginning of the ordering sequence:

@Test public void whenNullsFirst_thenSortedByNameWithNullsFirst() { Comparator employeeNameComparator = Comparator.comparing(Employee::getName); Comparator employeeNameComparator_nullFirst = Comparator.nullsFirst(employeeNameComparator); Arrays.sort(employeesArrayWithNulls, employeeNameComparator_nullFirst); assertTrue(Arrays.equals( employeesArrayWithNulls, sortedEmployeesArray_WithNullsFirst)); }

Let's see how the employees array values are ordered after the sort:

[null, null, Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

5.2. Considering Null Last

The nullsLast function will return a Comparator that keeps all nulls at the end of the ordering sequence:

@Test public void whenNullsLast_thenSortedByNameWithNullsLast() { Comparator employeeNameComparator = Comparator.comparing(Employee::getName); Comparator employeeNameComparator_nullLast = Comparator.nullsLast(employeeNameComparator); Arrays.sort(employeesArrayWithNulls, employeeNameComparator_nullLast); assertTrue(Arrays.equals( employeesArrayWithNulls, sortedEmployeesArray_WithNullsLast)); }

Let's see how the employees array values are ordered after the sort:

[Employee(name=Ace, age=22, salary=2000.0, mobile=5924001), Employee(name=John, age=25, salary=3000.0, mobile=9922001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401), null, null]

6. Using Comparator.thenComparing

The thenComparing function lets you set up lexicographical ordering of values by provisioning multiple sort keys in a particular sequence.

Let's consider another array of Employee class:

someMoreEmployees = new Employee[] { ... };

Consider the following sequence of elements in the above array:

[Employee(name=Jake, age=25, salary=3000.0, mobile=9922001), Employee(name=Jake, age=22, salary=2000.0, mobile=5924001), Employee(name=Ace, age=22, salary=3000.0, mobile=6423001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

Let's write a sequence of comparisons as age followed by the name and see the ordering of this array:

@Test public void whenThenComparing_thenSortedByAgeName(){ Comparator employee_Age_Name_Comparator = Comparator.comparing(Employee::getAge) .thenComparing(Employee::getName); Arrays.sort(someMoreEmployees, employee_Age_Name_Comparator); assertTrue(Arrays.equals(someMoreEmployees, sortedEmployeesByAgeName)); }

Here the ordering will be done by age, and for the values with the same age, ordering will be done by name. Let's observe this in the sequence we receive after sorting:

[Employee(name=Ace, age=22, salary=3000.0, mobile=6423001), Employee(name=Jake, age=22, salary=2000.0, mobile=5924001), Employee(name=Jake, age=25, salary=3000.0, mobile=9922001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

Let's use the other version of thenComparing that is thenComparingInt, by changing the lexicographical sequence to name followed by age:

@Test public void whenThenComparing_thenSortedByNameAge() { Comparator employee_Name_Age_Comparator = Comparator.comparing(Employee::getName) .thenComparingInt(Employee::getAge); Arrays.sort(someMoreEmployees, employee_Name_Age_Comparator); assertTrue(Arrays.equals(someMoreEmployees, sortedEmployeesByNameAge)); }

Let's see how the employees array values are ordered after the sort:

[Employee(name=Ace, age=22, salary=3000.0, mobile=6423001), Employee(name=Jake, age=22, salary=2000.0, mobile=5924001), Employee(name=Jake, age=25, salary=3000.0, mobile=9922001), Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]

Similarly, there are functions thenComparingLong and thenComparingDouble for using long and double sorting keys.

7. Conclusion

Artikel ini adalah panduan untuk beberapa ciri yang diperkenalkan di Java 8 untuk antara muka Perbandingan .

Seperti biasa, kod sumber boleh didapati di Github.