Java에서 Comparable 및 Comparator로 정렬

프로그래머는 종종 데이터베이스의 요소를 컬렉션, 배열 또는 맵으로 정렬해야합니다. Java에서는 모든 유형으로 원하는 정렬 알고리즘을 구현할 수 있습니다. 은 Using Comparable인터페이스와 compareTo()방법을, 우리는 일종의 알파벳 순서로 사용 할 수 있습니다 String길이, 알파벳 역순으로, 또는 숫자를. Comparator인터페이스는 우리가 동일하지만 좀 더 유연한 방법을 수행 할 수 있습니다.

우리가 원하는 것이 무엇이든, 주어진 인터페이스와 유형에 대해 올바른 정렬 로직을 구현하는 방법을 알면됩니다.

소스 코드 받기

이 Java Challenger에 대한 코드를 가져옵니다. 예제를 따르는 동안 자체 테스트를 실행할 수 있습니다.

사용자 정의 객체로 Java 목록 정렬

이 예에서는 지금까지 다른 Java Challenger에 사용했던 것과 동일한 POJO를 사용합니다. 이 첫 번째 예제에서는 제네릭 형식을 Simpson사용하여 클래스 에서 Comparable 인터페이스를 구현합니다 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 () 메서드를 재정의하고 다른 Simpson개체에 전달했습니다 . 또한 toString()예제를 더 쉽게 읽을 수 있도록 메서드를 재정의했습니다 .

toString메서드는 개체의 모든 정보를 표시합니다. 객체를 인쇄 할 때 출력은 toString().

compareTo () 메서드

compareTo()메서드는 지정된 개체 또는 현재 인스턴스를 지정된 개체와 비교하여 개체의 순서를 결정합니다. compareTo()작동 방식에 대한 간략한 설명 은 다음과 같습니다 .

  비교 결과가 반환되면

  그럼 ...

  >= 1

  this.name > simpson.name

  0

  this.name == simpson.name

  <= -1

  this.name < simpson.name

sort()메서드 와 비교할 수있는 클래스 만 사용할 수 있습니다 . Simpson구현하지 않는를 전달하려고 Comparable하면 컴파일 오류가 발생합니다.

sort()메서드는 인 객체를 전달하여 다형성을 사용합니다 Comparable. 그러면 개체가 예상대로 정렬됩니다.

이전 코드의 출력은 다음과 같습니다.

 Bart Homer Lisa Marge 

순서를 바꾸고 싶다면를 sort()a로 교환 할 수 있습니다 reverse(). 에서:

 Collections.sort(simpsons); 

에:

 Collections.reverse(simpsons); 

reverse()메서드를 배포하면 이전 출력이 다음과 같이 변경됩니다.

 Marge Lisa Homer Bart 

Java 배열 정렬

Java에서는 Comparable인터페이스를 구현하는 한 원하는 유형으로 배열을 정렬 할 수 있습니다 . 예를 들면 다음과 같습니다.

 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); } } 

첫 번째 sort()호출에서 배열은 다음과 같이 정렬됩니다.

 1 6 7 8 9 

두 번째 sort()호출에서는 다음과 같이 정렬됩니다.

 Homer Lisa 

Keep in mind that custom objects must implement Comparable in order to be sorted, even as an array.

Can I sort objects without Comparable?

If the Simpson object wasn’t implementing Comparable, a ClassCastException would be thrown. If you run this as a test, you will see something like the following output:

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

This log may be confusing, but don’t worry. Just keep in mind that a ClassCastException will be thrown for any sorted object that doesn’t implement the Comparable interface.

Sorting a Map with TreeMap

The Java API includes many classes to assist with sorting, including TreeMap. In the example below, we use TreeMap to sort keys into a 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); } } 

TreeMap uses the compareTo() method implemented by the Comparable interface. Each element in the resulting Map is sorted by its key. In this case, the output would be:

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

Remember, though: if the object doesn’t implement Comparable, a ClassCastException will be thrown.

Sorting a Set with TreeSet

The Set interface is responsible for storing unique values, but when we use the TreeSet implementation, inserted elements will be automatically sorted as we add them:

 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); } } 

The output from this code is:

 Barney, Homer, Lenny, Moe 

Again, if we use an object that is not Comparable, a ClassCastException will be thrown.

Sorting with Comparator

What if we didn’t want to use the same compareTo() method from the POJO class? Could we override the Comparable method to use a different logic? Below is an example:

 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.

비슷한 인터페이스에 도전하세요!

다음 코드의 출력을 확인하여 배운 내용을 테스트하십시오. 이 과제를 공부하는 것만으로도 스스로 해결한다면 가장 잘 배울 수 있다는 것을 기억하십시오. 답변에 도달하면 아래 답변을 확인할 수 있습니다. 개념을 완전히 흡수하기 위해 자체 테스트를 실행할 수도 있습니다.

 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; } } } 

이 코드의 출력은 무엇입니까?

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