수색…


통사론

  • 공용 클래스 MyClass는 Comparable <MyClass >
  • 공용 클래스 MyComparator는 Comparator <SomeOtherClass >
  • 공용 int compareTo (MyClass 기타)
  • 공용 int compare (SomeOtherClass o1, SomeOtherClass o2)

비고

double 의존하는 compareTo(..) 메서드를 구현할 때는 다음을 수행하지 마십시오.

public int comareTo(MyClass other) {
    return (int)(doubleField - other.doubleField); //THIS IS BAD
}

(int) 인한 잘림은 메서드가 양수 또는 음수 대신 0 잘못 반환하는 경우가 발생하므로 비교 및 ​​정렬 버그가 발생할 수 있습니다.

대신 Double.compare를 다음 과 같이 사용하는 것이 가장 간단합니다.

public int comareTo(MyClass other) {
    return Double.compare(doubleField,other.doubleField); //THIS IS GOOD
} 

의 제네릭이 아닌 버전은 Comparable<T> , 단순히 Comparable , 자바 1.2부터 존재했다 . 레거시 코드와 인터페이싱하는 것 이외에, 비교시 캐스팅 할 필요가 없기 때문에 제네릭 버전 인 Comparable<T> 을 구현하는 것이 항상 더 좋습니다.


그것은 다음과 같이 클래스가 자신과 비교할 수있는 표준입니다.

public class A implements Comparable<A>

이 패러다임에서 벗어날 수는 있지만 그렇게 할 때는주의해야합니다.


그 클래스가 Comparable<T> 구현하고있는 경우, Comparator<T> 는 클래스의 인스턴스로 계속 사용할 수 있습니다. 이 경우 Comparator 의 로직이 사용됩니다. Comparable 구현에 의해 지정된 자연 순서 부가 무시됩니다.

Comparable을 사용하여 목록 정렬 또는 비교기

Person을 대표하는 클래스를 성과 이름으로 작업한다고 가정 해 보겠습니다. 우리는 이것을 수행하고 적절한 equalshashCode 메소드를 구현하기위한 기본 클래스를 작성했습니다.

public class Person {

    private final String lastName; //invariant - nonnull
    private final String firstName; //invariant - nonnull

    public Person(String firstName, String lastName){
        this.firstName = firstName != null ? firstName : "";
        this.lastName = lastName != null ? lastName : "";
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String toString() {
        return lastName + ", " + firstName;
    }

    @Override
    public boolean equals(Object o) {
        if (! (o instanceof Person)) return false;
        Person p = (Person)o;
        return firstName.equals(p.firstName) && lastName.equals(p.lastName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName);
    }
}

이제 다음과 같은 경우와 같이 이름으로 Person 객체 목록을 정렬하려고합니다.

public static void main(String[] args) {
    List<Person> people = Arrays.asList(new Person("John", "Doe"),
                                     new Person("Bob", "Dole"),
                                     new Person("Ronald", "McDonald"),
                                     new Person("Alice", "McDonald"),
                                     new Person("Jill", "Doe"));
    Collections.sort(people); //This currently won't work.
}

불행히도, 표시된대로, 위의 현재 컴파일되지 않습니다. Collections.sort(..) 는 목록의 요소가 비교 가능하거나 비교의 사용자 지정 메서드가 제공되는 경우에만 목록을 정렬하는 방법을 알고 있습니다.

다음 목록을 정렬하라는 요청을 받았다면 : 1,3,5,4,2 , 대답은 1,2,3,4,5 라고 말할 수 있습니다. 이는 정수 (Java 및 수학 모두)가 자연 순서 (natural ordering ), 표준 기본 비교 기본 순서를 가지기 때문입니다. Person 클래스에 자연스러운 순서를 부여하기 위해 compareTo(Person p): 메소드를 구현해야하는 Comparable<Person> 구현합니다 compareTo(Person p):

public class Person implements Comparable<Person> {

    private final String lastName; //invariant - nonnull
    private final String firstName; //invariant - nonnull

    public Person(String firstName, String lastName) {
        this.firstName = firstName != null ? firstName : "";
        this.lastName = lastName != null ? lastName : "";
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String toString() {
        return lastName + ", " + firstName;
    }

    @Override
    public boolean equals(Object o) {
        if (! (o instanceof Person)) return false;
        Person p = (Person)o;
        return firstName.equals(p.firstName) && lastName.equals(p.lastName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName);
    }

    @Override
    public int compareTo(Person other) {
        // If this' lastName and other's lastName are not comparably equivalent,
        // Compare this to other by comparing their last names.
        // Otherwise, compare this to other by comparing their first names
        int lastNameCompare = lastName.compareTo(other.lastName);
        if (lastNameCompare != 0) {
            return lastNameCompare;
        } else {
            return firstName.compareTo(other.firstName);
        }
    }
}

이제 주어진 주 방법이 올바르게 작동합니다.

public static void main(String[] args) {
    List<Person> people = Arrays.asList(new Person("John", "Doe"),
                                     new Person("Bob", "Dole"),
                                     new Person("Ronald", "McDonald"),
                                     new Person("Alice", "McDonald"),
                                     new Person("Jill", "Doe"));
    Collections.sort(people); //Now functions correctly

    //people is now sorted by last name, then first name:
    // --> Jill Doe, John Doe, Bob Dole, Alice McDonald, Ronald McDonald
}

그러나 클래스 Person 을 원하지 않거나 수정할 수없는 경우, 두 Person 오브젝트의 비교를 처리하는 사용자 정의 Comparator<T> 를 제공 할 수 있습니다. circle, square, rectangle, triangle, hexagon 목록을 정렬하라는 요청을 받았지만 모서리 수에 따라 목록을 정렬하도록 요청한 경우 그렇게 할 수 있습니다. 마찬가지로, 비교자를 제공하면 자바에게 비교할 수없는 두 객체를 비교하는 방법을 지시합니다.

public class PersonComparator implements Comparator<Person> {

    public int compare(Person p1, Person p2) {
        // If p1's lastName and p2's lastName are not comparably equivalent,
        // Compare p1 to p2 by comparing their last names.
        // Otherwise, compare p1 to p2 by comparing their first names
        if (p1.getLastName().compareTo(p2.getLastName()) != 0) {
            return p1.getLastName().compareTo(p2.getLastName());
        } else {
            return p1.getFirstName().compareTo(p2.getFirstName());
        }
    }
}

//Assume the first version of Person (that does not implement Comparable) is used here
public static void main(String[] args) {
    List<Person> people = Arrays.asList(new Person("John", "Doe"),
                                     new Person("Bob", "Dole"),
                                     new Person("Ronald", "McDonald"),
                                     new Person("Alice", "McDonald"),
                                     new Person("Jill", "Doe"));
    Collections.sort(people); //Illegal, Person doesn't implement Comparable.
    Collections.sort(people, new PersonComparator()); //Legal

    //people is now sorted by last name, then first name:
    // --> Jill Doe, John Doe, Bob Dole, Alice McDonald, Ronald McDonald
}

Comparator는 익명의 내부 클래스로 생성 / 사용될 수도 있습니다.

//Assume the first version of Person (that does not implement Comparable) is used here
public static void main(String[] args) {
    List<Person> people = Arrays.asList(new Person("John", "Doe"),
                                     new Person("Bob", "Dole"),
                                     new Person("Ronald", "McDonald"),
                                     new Person("Alice", "McDonald"),
                                     new Person("Jill", "Doe"));
    Collections.sort(people); //Illegal, Person doesn't implement Comparable.

    Collections.sort(people, new PersonComparator()); //Legal

    //people is now sorted by last name, then first name:
    // --> Jill Doe, John Doe, Bob Dole, Alice McDonald, Ronald McDonald

    //Anonymous Class
    Collections.sort(people, new Comparator<Person>() { //Legal
        public int compare(Person p1, Person p2) {
            //Method code...
        }
    });
}
Java SE 8

람다 식 기반 비교기

자바 8에서, 비교기는 또한 람다 표현식으로 표현 될 수있다.

    //Lambda
    Collections.sort(people, (p1, p2) -> { //Legal
        //Method code....
    });

Comparator의 디폴트 메소드

게다가 Comparator를 구현하기위한 Comparator 인터페이스에는 흥미로운 기본 메소드가 있습니다. 다음은 lastNamefirstName 비교하는 비교기를 작성합니다.

Collections.sort(people, Comparator.comparing(Person::getLastName)
                                .thenComparing(Person::getFirstName));

비교기의 순서 반전

모든 비교자를 오름차순에서 내림차순으로 변경하는 reversedMethod 를 사용하여 쉽게 되돌릴 수 있습니다.

compareTo 및 compare 메소드

Comparable<T> 인터페이스에는 다음과 같은 메서드가 필요합니다.

public interface Comparable<T> {

    public int compareTo(T other);

}

그리고 Comparator<T> 인터페이스에는 다음과 같은 한 가지 방법이 필요합니다.

public interface Comparator<T> {

    public int compare(T t1, T t2);

}

:이 두 가지 방법은 하나 개의 작은 차이가 본질적으로 같은 일을 할 compareTo 비교 thisother 반면, compare 비교 t1t2 하지 돌보는 모두에 대해 this .

이 두 가지 방법을 제외하고는 비슷한 차이점이 있습니다. 특히 (compareTo의 경우), 이 오브젝트를 지정된 오브젝트와 비교해 순서 붙일 수 있습니다. 이 객체가 지정된 객체보다 작거나 같거나 큰 경우 음수, 0 또는 양의 정수를 반환합니다. 따라서, ab 의 비교를 a :

  • a < b , a.compareTo(b)compare(a,b) 가 음의 정수를 반환하고 b.compareTo(a)compare(b,a) 가 양의 정수를 반환해야하는 경우
  • a > b , a.compareTo(b)compare(a,b) 가 양의 정수를 반환하고 b.compareTo(a)compare(b,a) 가 음의 정수를 반환해야하는 경우
  • 경우 a 동일 b 비교를 위해, 모든 비교는 반환해야합니다 0 .

자연 (비교 가능) 대 명시 (비교 자) 정렬

두 개의 Collections.sort() 메소드가 있습니다.

  • 하나는 List<T>T 가 Comparable을 구현해야하는 매개 변수로 취하고 정렬 순서를 결정하는 compareTo() 메서드를 재정의합니다.
  • Comparator가 정렬 순서를 결정하는 List 및 Comparator를 인수로 취하는 메서드

첫째, Comparable을 구현 한 Person 클래스가있다.

public class Person implements Comparable<Person> {         
    private String name;  
    private int age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }         

    @Override
    public int compareTo(Person o) {
        return this.getAge() - o.getAge();
    }
    @Override
    public String toString() {
        return this.getAge()+"-"+this.getName();
    }

}

위의 클래스를 사용하여 compareTo() 메서드 재정의에 의해 정의 된 요소의 자연 순서로 목록을 정렬하는 방법은 다음과 같습니다.

//-- usage
List<Person> pList = new ArrayList<Person>();
            Person p = new Person();
            p.setName("A");
            p.setAge(10);
            pList.add(p);
            p = new Person();
            p.setName("Z");
            p.setAge(20);
            pList.add(p);
            p = new Person();
            p.setName("D");
            p.setAge(30);
            pList.add(p);
            
            //-- natural sorting i.e comes with object implementation, by age
            Collections.sort(pList);

            System.out.println(pList);

다음은 익명 인라인 Comparator를 사용하여 Comparable을 구현하지 않는 List를 정렬하거나이 경우 자연 정렬과 다른 순서로 List를 정렬하는 방법입니다.

            //-- explicit sorting, define sort on another property here goes with name
            Collections.sort(pList, new Comparator<Person>() {

                @Override
                public int compare(Person o1, Person o2) {
                    return o1.getName().compareTo(o2.getName());
                }
            });            
            System.out.println(pList);

지도 항목 정렬

Java 8의 경우 map 반복을 정렬 할 수 있도록 Map.Entry 인터페이스에 기본 메소드가 있습니다.

Java SE 8
Map<String, Integer> numberOfEmployees = new HashMap<>();
numberOfEmployees.put("executives", 10);
numberOfEmployees.put("human ressources", 32);
numberOfEmployees.put("accounting", 12);
numberOfEmployees.put("IT", 100);

// Output the smallest departement in terms of number of employees
numberOfEmployees.entrySet().stream()
    .sorted(Map.Entry.comparingByValue())
    .limit(1)
    .forEach(System.out::println);   // outputs : executives=10

물론 스트림 API 외부에서 사용할 수도 있습니다.

Java SE 8
List<Map.Entry<String, Integer>> entries = new ArrayList<>(numberOfEmployees.entrySet());
Collections.sort(entries, Map.Entry.comparingByValue());

비교 메서드를 사용하여 Comparator 만들기

Comparator.comparing(Person::getName)

이것은이 사람 이름을 비교 소스로 사용하는 Person 클래스에 대한 비교자를 생성합니다. 또한 메서드 버전을 사용하여 long, int 및 double을 비교할 수 있습니다. 예 :

Comparator.comparingInt(Person::getAge)

역 주문

역순을 부과하는 컴퍼 레이터를 작성하려면, reversed() 메소드를 사용합니다.

Comparator.comparing(Person::getName).reversed()

비교기 체인

Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName)

이렇게하면 firs와 성을 비교 한 다음 이름과 비교하는 비교자를 생성합니다. 원하는만큼 많은 비교기를 연결할 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow