Panduan untuk Java 8 Comparator.comparing ()

1. Ikhtisar

Java 8 memperkenalkan beberapa peningkatan pada antarmuka Comparator , termasuk beberapa fungsi statis yang sangat berguna saat membuat urutan koleksi.

Java 8 lambda dapat dimanfaatkan secara efektif dengan antarmuka Comparator juga. Penjelasan rinci tentang lambda dan Pembanding dapat ditemukan di sini, dan kronik tentang penyortiran dan aplikasi Pembanding dapat ditemukan di sini.

Dalam tutorial ini, kita akan menjelajahi beberapa fungsi yang diperkenalkan untuk antarmuka Comparator di Java 8 .

2. Memulai

2.1. Contoh Kelas Kacang

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

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

2.2. Data Pengujian Kami

Mari kita juga membuat array karyawan yang akan digunakan untuk menyimpan hasil tipe kita dalam berbagai kasus pengujian di seluruh artikel:

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

Urutan awal elemen karyawan 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 menyortir di atas array Karyawan menggunakan fungsi yang berbeda.

Untuk pernyataan pengujian, kita akan menggunakan satu set array yang telah diurutkan yang akan kita bandingkan dengan hasil sortir kita (yaitu, array karyawan ) untuk skenario yang berbeda.

Mari nyatakan beberapa larik ini:

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

Seperti biasa, silakan merujuk tautan GitHub kami untuk kode lengkap.

3. Menggunakan Comparator.comparing

Bagian ini membahas varian dari fungsi statis Comparator.comparing .

3.1. Varian Pemilih Kunci

The Comparator.comparing fungsi statis menerima semacam kunci Fungsi dan mengembalikan komparator untuk jenis yang berisi kunci semacam:

static 
    
      Comparator comparing( Function keyExtractor)
    

Untuk melihat ini beraksi, mari gunakan kolom name di Employee sebagai kunci sortir dan berikan referensi metodenya sebagai argumen bertipe Function. The Pembanding kembali dari yaitu sama yang digunakan untuk menyortir:

@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 array karyawan diurutkan berdasarkan nama sebagai hasil dari pengurutan:

[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. Pemilih Kunci dan Varian Pembanding

Ada opsi lain yang memfasilitasi penggantian pengurutan natural dari kunci pengurutan dengan menyediakan Pembanding yang membuat pengurutan kustom untuk kunci pengurutan:

static  Comparator comparing( Function keyExtractor, Comparator keyComparator)

Mari kita ubah pengujian di atas, menimpa urutan alami pengurutan menurut bidang nama dengan menyediakan Pembanding untuk mengurutkan nama dalam urutan menurun sebagai argumen 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, hasil diurutkan dalam urutan menurun menurut 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

When invoked on an existing Comparator, the instance method Comparator.reversed returns a new Comparator that reverses the sort order of the original.

Let's use the Comparator that sorts the employees by name and reverse it so that employees are sorted in descending order of the name:

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

The results are sorted in descending order by name:

[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. Using Comparator.comparingInt

There is also a function Comparator.comparingInt which does the same thing as Comparator.comparing, but it takes only int selectors. Let's try this with an example where we order employees by age:

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

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)]

3.5. Using Comparator.comparingLong

Similar to what we did for int keys, let's see an example using Comparator.comparingLong to consider a sort key of type long by ordering the employees array by the mobile field:

@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 fitur yang diperkenalkan di Java 8 untuk antarmuka Comparator .

Seperti biasa, kode sumber dapat ditemukan di Github.