Pembanding dan Sebanding di Jawa

1. Pengenalan

Perbandingan di Java cukup mudah - sehingga tidak.

Ketika bekerja dengan jenis khusus, atau mencoba membandingkan objek yang tidak dapat dibandingkan secara langsung, kita harus memanfaatkan strategi perbandingan. Kita boleh membuatnya dengan sederhana, tetapi menggunakan antara muka Perbandingan atau Komparasi .

2. Menetapkan Contoh

Mari kita ambil contoh pasukan bola sepak - di mana kita mahu membariskan pemain mengikut kedudukan mereka.

Kami akan mulakan dengan membuat kelas Pemain sederhana :

public class Player { private int ranking; private String name; private int age; // constructor, getters, setters }

Seterusnya, mari buat kelas PlayerSorter untuk membuat koleksi kami dan membuat percubaan untuk menyusunnya menggunakan Collections.sort :

public static void main(String[] args) { List footballTeam = new ArrayList(); Player player1 = new Player(59, "John", 20); Player player2 = new Player(67, "Roger", 22); Player player3 = new Player(45, "Steven", 24); footballTeam.add(player1); footballTeam.add(player2); footballTeam.add(player3); System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam); System.out.println("After Sorting : " + footballTeam); } 

Di sini, seperti yang diharapkan, ini menghasilkan ralat waktu kompilasi:

The method sort(List) in the type Collections is not applicable for the arguments (ArrayList)

Mari kita fahami apa yang kita buat salah di sini.

3. Setanding

Seperti namanya, Comparable adalah antara muka yang menentukan strategi membandingkan objek dengan objek lain dari jenis yang sama. Ini disebut "susunan semula jadi" kelas.

Oleh itu, untuk dapat menyusun - kita mesti menentukan objek Pemain kita sebagai setanding dengan melaksanakan antara muka yang Sebanding :

public class Player implements Comparable { // same as before @Override public int compareTo(Player otherPlayer) { return Integer.compare(getRanking(), otherPlayer.getRanking()); } } 

Urutan penyusun ditentukan oleh nilai kembali kaedah perbandinganTo () . The Integer.compare (x, y) pulangan -1 jika x adalah kurang daripada y , mengembalikan 0 jika mereka sama, dan mengembalikan 1 sebaliknya.

Kaedah mengembalikan nombor yang menunjukkan sama ada objek yang dibandingkan kurang dari, sama dengan, atau lebih besar daripada objek yang dilalui sebagai argumen.

Akhirnya, apabila kita menjalankan PlayerSorter kita sekarang, kita dapat melihat Pemain kami disusun mengikut kedudukan mereka:

Before Sorting : [John, Roger, Steven] After Sorting : [Steven, John, Roger]

Sekarang kita mempunyai pemahaman yang jelas mengenai pesanan semula jadi dengan Sebanding , mari kita lihat bagaimana kita dapat menggunakan jenis pesanan lain, dengan cara yang lebih fleksibel daripada secara langsung melaksanakan antara muka.

4. Pembanding

Antara muka Perbandingan menentukan kaedah perbandingan (arg1, arg2) dengan dua argumen yang mewakili objek yang dibandingkan dan berfungsi sama dengan kaedah Comparable.compareTo () .

4.1. Membuat Perbandingan

Untuk membuat Comparator, kita harus melaksanakan antara muka Comparator .

Dalam contoh pertama kami, kami akan membuat Perbandingan untuk menggunakan atribut ranking Pemain untuk menyusun pemain:

public class PlayerRankingComparator implements Comparator { @Override public int compare(Player firstPlayer, Player secondPlayer) { return Integer.compare(firstPlayer.getRanking(), secondPlayer.getRanking()); } }

Begitu juga, kita boleh membuat Perbandingan untuk menggunakan atribut umur Pemain untuk menyusun pemain:

public class PlayerAgeComparator implements Comparator { @Override public int compare(Player firstPlayer, Player secondPlayer) { return Integer.compare(firstPlayer.getAge(), secondPlayer.getAge()); } }

4.2. Pembanding dalam Tindakan

Untuk menunjukkan konsep, mari kita ubah PlayerSorter kami dengan memperkenalkan argumen kedua kepada kaedah Collections.sort yang sebenarnya merupakan contoh Comparator yang ingin kita gunakan.

Dengan menggunakan pendekatan ini, kita dapat mengatasi urutan semula jadi :

PlayerRankingComparator playerComparator = new PlayerRankingComparator(); Collections.sort(footballTeam, playerComparator); 

Sekarang, mari jalankan PlayerRankingSorter kami untuk melihat hasilnya:

Before Sorting : [John, Roger, Steven] After Sorting by ranking : [Steven, John, Roger]

Sekiranya kita mahukan urutan penyortiran yang berbeza, kita hanya perlu menukar Perbandingan yang kita gunakan:

PlayerAgeComparator playerComparator = new PlayerAgeComparator(); Collections.sort(footballTeam, playerComparator);

Sekarang, semasa kita menjalankan PlayerAgeSorter , kita dapat melihat urutan yang berbeza mengikut umur:

Before Sorting : [John, Roger, Steven] After Sorting by age : [Roger, John, Steven]

4.3. Pembanding Java 8

Java 8 menyediakan kaedah baru untuk menentukan Perbandingan dengan menggunakan ungkapan lambda dan membandingkan () kaedah kilang statik.

Mari lihat contoh ringkas bagaimana menggunakan ungkapan lambda untuk membuat Perbandingan :

Comparator byRanking = (Player player1, Player player2) -> Integer.compare(player1.getRanking(), player2.getRanking());

The Comparator.comparing kaedah mengambil kaedah mengira harta yang akan digunakan untuk membandingkan barangan, dan mengembalikan sepadan Comparator contoh:

Comparator byRanking = Comparator .comparing(Player::getRanking); Comparator byAge = Comparator .comparing(Player::getAge);

Anda boleh meneroka fungsi Java 8 secara mendalam di panduan perkongsian Java 8 Comparator.com kami.

5. Pembanding vs Berbanding

Antara muka yang boleh dibandingkan adalah pilihan yang baik ketika digunakan untuk menentukan pesanan lalai atau, dengan kata lain, jika itu adalah cara utama membandingkan objek.

Kemudian, kita mesti bertanya kepada diri sendiri mengapa menggunakan Perbandingan jika kita sudah mempunyai Perbandingan ?

Terdapat beberapa sebab mengapa:

  • Sometimes, we can't modify the source code of the class whose objects we want to sort, thus making the use of Comparable impossible
  • Using Comparators allows us to avoid adding additional code to our domain classes
  • We can define multiple different comparison strategies which isn't possible when using Comparable

6. Avoiding the Subtraction Trick

Over the course of this tutorial, we used the Integer.compare() method to compare two integers. One might argue that we should use this clever one-liner instead:

Comparator comparator = (p1, p2) -> p1.getRanking() - p2.getRanking();

Although it's much more concise compared to other solutions, it can be a victim of integer overflows in Java:

Player player1 = new Player(59, "John", Integer.MAX_VALUE); Player player2 = new Player(67, "Roger", -1); List players = Arrays.asList(player1, player2); players.sort(comparator);

Since -1 is much less than the Integer.MAX_VALUE, “Roger” should come before the “John” in the sorted collection. However, due to integer overflow, the “Integer.MAX_VALUE – (-1)” will be less than zero. So, based on the Comparator/Comparable contract, the Integer.MAX_VALUE is less than -1, which is obviously incorrect.

Hence, despite what we expected, “John” comes before the “Roger” in the sorted collection:

assertEquals("John", players.get(0).getName()); assertEquals("Roger", players.get(1).getName());

7. Conclusion

In this tutorial, we explored the Comparable and Comparator interfaces and discussed the differences between them.

To understand more advanced topics of sorting, check out our other articles such as Java 8 Comparator, Java 8 Comparison with Lambdas.

Dan, seperti biasa, kod sumber boleh didapati di GitHub.