Java'da Comparable ve Comparator ile Sıralama

Programcıların sık sık bir veritabanındaki öğeleri bir koleksiyona, diziye veya haritaya ayırması gerekir. Java'da, herhangi bir tür ile istediğimiz sıralama algoritmasını uygulayabiliriz. Kullanma Comparablearayüzü ve compareTo()yöntemi, bir nevi alfabetik kullanarak olabilir Stringuzunluğu, ters alfabetik veya sayıları. ComparatorArayüz bize aynı ama daha esnek bir şekilde yapmanızı sağlar.

Ne yapmak istersek, sadece verilen arayüz ve tip için doğru sıralama mantığını nasıl uygulayacağımızı bilmemiz gerekir.

Kaynak kodunu alın

Bu Java Challenger kodunu alın. Örnekleri takip ederken kendi testlerinizi de yapabilirsiniz.

Java Listesini özel bir nesneyle sıralama

Örneğimiz için şimdiye kadar diğer Java Challenger'lar için kullandığımız POJO'yu kullanacağız. Bu ilk örnekte, genel türü Simpsonkullanarak Comparable arabirimini sınıfta uyguluyoruz Simpson:

 class Simpson implements Comparable { String name; Simpson(String name) { this.name = name; } @Override public int compareTo(Simpson simpson) { return this.name.compareTo(simpson.name); } } public class SimpsonSorting { public static void main(String... sortingWithList) { List simpsons = new ArrayList(); simpsons.add(new SimpsonCharacter("Homer ")); simpsons.add(new SimpsonCharacter("Marge ")); simpsons.add(new SimpsonCharacter("Bart ")); simpsons.add(new SimpsonCharacter("Lisa ")); Collections.sort(simpsons); simpsons.stream().map(s -> s.name).forEach(System.out::print); Collections.reverse(simpsons); simpsons.stream().forEach(System.out::print); } } 

CompareTo () yöntemini geçersiz kıldığımızı ve başka bir Simpsonnesnede geçirdiğimizi unutmayın . Ayrıca toString(), örneğin daha kolay okunmasını sağlamak için yöntemi de geçersiz kıldık .

toStringTüm usul gösterir nesneden bilgiler. Nesneyi yazdırdığımızda çıktı, içinde uygulanan her şey olacaktır toString().

CompareTo () yöntemi

compareTo()Yöntem, nesne sırasını belirlemek için belirli bir nesne ile, belirli bir nesne veya akım örneğini karşılaştırır. İşte nasıl compareTo()çalıştığına hızlı bir bakış :

  Karşılaştırma geri dönerse

  Sonra ...

  >= 1

  this.name > simpson.name

  0

  this.name == simpson.name

  <= -1

  this.name < simpson.name

Sadece sort()metotla karşılaştırılabilir sınıfları kullanabiliriz . SimpsonUygulanmayan bir geçmeye çalışırsak Comparable, bir derleme hatası alacağız.

sort()Yöntem herhangi bir nesneye geçirilerek polimorfizm kullanır Comparable. Nesneler daha sonra beklendiği gibi sıralanacaktır.

Önceki kodun çıktısı şöyle olacaktır:

 Bart Homer Lisa Marge 

Emri tersine çevirmek isteseydik, sort()a reverse(); from:

 Collections.sort(simpsons); 

to:

 Collections.reverse(simpsons); 

reverse()Yöntemin dağıtılması, önceki çıktıyı şu şekilde değiştirir:

 Marge Lisa Homer Bart 

Bir Java dizisini sıralama

Java'da, Comparablearayüzü uyguladığı sürece istediğimiz türden bir diziyi sıralayabiliriz . İşte bir örnek:

 public class ArraySorting { public static void main(String... moeTavern) { int[] moesPints = new int[] {9, 8, 7, 6, 1}; Arrays.sort(moesPints); Arrays.stream(moesPints).forEach(System.out::print); Simpson[] simpsons = new Simpson[]{new Simpson("Lisa"), new Simpson("Homer")}; Arrays.sort(simpsons); Arrays.stream(simpsons).forEach(System.out::println); } } 

İlk sort()çağrıda dizi şu şekilde sıralanır:

 1 6 7 8 9 

İkinci sort()çağrıda şu şekilde sıralanır:

 Homer Lisa 

Özel nesnelerin Comparablebir dizi olarak bile sıralanabilmesi için uygulaması gerektiğini unutmayın .

Karşılaştırılabilir olmadan nesneleri sıralayabilir miyim?

Simpson nesnesi uygulanmıyorsa Comparable, bir ClassCastException atılır. Bunu bir test olarak çalıştırırsanız, aşağıdaki çıktıya benzer bir şey göreceksiniz:

 Error:(16, 20) java: no suitable method found for sort(java.util.List) method java.util.Collections.sort(java.util.List) is not applicable (inference variable T has incompatible bounds equality constraints: com.javaworld.javachallengers.sortingcomparable.Simpson lower bounds: java.lang.Comparable) method java.util.Collections.sort(java.util.List,java.util.Comparator) is not applicable (cannot infer type-variable(s) T (actual and formal argument lists differ in length)) 

Bu günlük kafa karıştırıcı olabilir, ancak endişelenmeyin. Arabirimi ClassCastExceptionuygulamayan herhangi bir sıralı nesne için atılacağını unutmayın Comparable.

Bir Haritayı TreeMap ile Sıralama

Java API, TreeMap dahil, sıralamaya yardımcı olacak birçok sınıf içerir. Aşağıdaki örnekte, TreeMapanahtarları bir Map.

 public class TreeMapExample { public static void main(String... barney) { Map simpsonsCharacters = new TreeMap(); simpsonsCharacters.put(new SimpsonCharacter("Moe"), "shotgun"); simpsonsCharacters.put(new SimpsonCharacter("Lenny"), "Carl"); simpsonsCharacters.put(new SimpsonCharacter("Homer"), "television"); simpsonsCharacters.put(new SimpsonCharacter("Barney"), "beer"); System.out.println(simpsonsCharacters); } } 

TreeMaparayüz compareTo()tarafından uygulanan yöntemi kullanır Comparable. Sonuçtaki her öğe Map, anahtarına göre sıralanır. Bu durumda çıktı:

 Barney=beer, Homer=television, Lenny=Carl, Moe=shotgun 

Yine de unutmayın: nesne uygulanmazsa Comparable, a ClassCastExceptionatılacaktır.

Bir Seti TreeSet ile Sıralama

SetArayüz benzersiz değerler depolamak için sorumlu, ama biz TreeSet uygulanmasını kullandığınızda ekleyebilirsiniz olarak, eklenen elemanlar otomatik olarak sıralanır:

 public class TreeSetExample { public static void main(String... barney) { Set simpsonsCharacters = new TreeSet(); simpsonsCharacters.add(new SimpsonCharacter("Moe")); simpsonsCharacters.add(new SimpsonCharacter("Lenny")); simpsonsCharacters.add(new SimpsonCharacter("Homer")); simpsonsCharacters.add(new SimpsonCharacter("Barney")); System.out.println(simpsonsCharacters); } } 

Bu kodun çıktısı:

 Barney, Homer, Lenny, Moe 

Yine, olmayan bir nesne kullanırsak Comparable, a ClassCastExceptionatılır.

Karşılaştırıcı ile Sıralama

Ya compareTo()POJO sınıfından aynı yöntemi kullanmak istemezsek ? ComparableFarklı bir mantık kullanmak için yöntemi geçersiz kılabilir miyiz ? Aşağıda bir örnek verilmiştir:

 public class BadExampleOfComparable { public static void main(String... args) { List characters = new ArrayList(); SimpsonCharacter homer = new SimpsonCharacter("Homer") { @Override public int compareTo(SimpsonCharacter simpson) { return this.name.length() - (simpson.name.length()); } }; SimpsonCharacter moe = new SimpsonCharacter("Moe") { @Override public int compareTo(SimpsonCharacter simpson) { return this.name.length() - (simpson.name.length()); } }; characters.add(homer); characters.add(moe); Collections.sort(characters); System.out.println(characters); } } 

As you can see, this code is complicated and includes a lot of repetition. We had to override the compareTo() method twice for the same logic. If there were more elements we would have to replicate the logic for each object.

Fortunately, we have the Comparator interface, which lets us detach the compareTo() logic from Java classes. Consider the same example above rewritten using Comparator:

 public class GoodExampleOfComparator { public static void main(String... args) { List characters = new ArrayList(); SimpsonCharacter homer = new SimpsonCharacter("Homer"); SimpsonCharacter moe = new SimpsonCharacter("Moe"); characters.add(homer); characters.add(moe); Collections.sort(characters, (Comparator. comparingInt(character1 -> character1.name.length()) .thenComparingInt(character2 -> character2.name.length()))); System.out.println(characters); } } 

These examples demonstrate the main difference between Comparable and Comparator.

Use Comparable when there is a single, default comparison for your object. Use Comparatorwhen you need to work around an existing compareTo(), or when you need to use specific logic in a more flexible way. Comparator detaches the sorting logic from your object and contains the compareTo() logic within your sort() method.

Using Comparator with an anonymous inner class

In this next example, we use an anonymous inner class to compare the value of objects. An anonymous inner class, in this case, is any class that implements Comparator. Using it means we are not bound to instantiating a named class implementing an interface; instead, we implement the compareTo() method inside the anonymous inner class.

 public class MarvelComparator { public static void main(String... comparator) { List marvelHeroes = new ArrayList(); marvelHeroes.add("SpiderMan "); marvelHeroes.add("Wolverine "); marvelHeroes.add("Xavier "); marvelHeroes.add("Cyclops "); Collections.sort(marvelHeroes, new Comparator() { @Override public int compare(String hero1, String hero2) { return hero1.compareTo(hero2); } }); Collections.sort(marvelHeroes, (m1, m2) -> m1.compareTo(m2)); Collections.sort(marvelHeroes, Comparator.naturalOrder()); marvelHeroes.forEach(System.out::print); } } 

More about inner classes

An anonymous inner class is simply any class whose name doesn’t matter, and which implements the interface we are declaring. So in the example, the new Comparator is actually the instantiation of a class that doesn’t have a name, which implements the method with the logic we want.

Using Comparator with lambda expressions

Anonymous inner classes are verbose, which can cause problems in our code. In the Comparator interface, we can use lambda expressions to simplify and make the code easier to read. For example, we could change this:

 Collections.sort(marvel, new Comparator() { @Override public int compare(String hero1, String hero2) { return hero1.compareTo(hero2); } }); 

to this:

 Collections.sort(marvel, (m1, m2) -> m1.compareTo(m2)); 

Less code and the same result!

The output of this code would be:

 Cyclops SpiderMan Wolverine Xavier 

We could make the code even simpler by changing this:

 Collections.sort(marvel, (m1, m2) -> m1.compareTo(m2)); 

to this:

 Collections.sort(marvel, Comparator.naturalOrder()); 

Lambda expressions in Java

Learn more about lambda expressions and other functional programming techniques in Java.

Are the core Java classes Comparable?

Many core Java classes and objects implement the Comparable interface, which means we don’t have to implement the compareTo() logic for those classes. Here are a few familiar examples:

String

 public final class String implements java.io.Serializable, Comparable, CharSequence { ... 

Integer

 public final class Integer extends Number implements Comparable { … 

Double

 public final class Double extends Number implements Comparable {... 

There are many others. I encourage you to explore the Java core classes to learn their important patterns and concepts.

Karşılaştırılabilir arayüz meydan okumasına katılın!

Aşağıdaki kodun çıktısını hesaplayarak öğrendiklerinizi test edin. Unutma, bu zorluğu sadece çalışarak çözersen en iyi öğreneceksin. Bir cevaba ulaştığınızda, aşağıdaki cevabı kontrol edebilirsiniz. Kavramları tamamen özümsemek için kendi testlerinizi de çalıştırabilirsiniz.

 public class SortComparableChallenge { public static void main(String... doYourBest) { Set set = new TreeSet(); set.add(new Simpson("Homer")); set.add(new Simpson("Marge")); set.add(new Simpson("Lisa")); set.add(new Simpson("Bart")); set.add(new Simpson("Maggie")); List list = new ArrayList(); list.addAll(set); Collections.reverse(list); list.forEach(System.out::println); } static class Simpson implements Comparable { String name; public Simpson(String name) { this.name = name; } public int compareTo(Simpson simpson) { return simpson.name.compareTo(this.name); } public String toString() { return this.name; } } } 

Bu kodun çıktısı nedir?

 A) Bart Homer Lisa Maggie Marge B) Maggie Bart Lisa Marge Homer C) Marge Maggie Lisa Homer Bart D) Indeterminate