JAVA——ComparableインタフェースとComparatorインタフェースの違い


JAVA——ComparableインタフェースとComparatorインタフェースの違いComparableインタフェースComparableはソートインタフェースです.1つのクラスがComparableインタフェースを実装し、すなわち、クラスがcompareToメソッドを実装したことを表す場合、このメソッドは、クラスのオブジェクトの比較規則(2つのオブジェクトが「サイズ」をどのように比較するか)を規定する.クラスは、o1.compareTo(o2)メソッドを実装することによって、o1およびo2のサイズを比較する.
  • が正数を返すと、o1o2より大きいことを意味する.
  • 負数を返すと、o1o2より小さいことを意味する.
  • がゼロに戻ると、o1o2に等しいことを意味する.
  • ComparatorインタフェースComparatorはコンパレータインターフェースである.特定のオブジェクトの順序を制御するだけで、クラス自体がソートをサポートしていない(すなわち、Comparableインタフェースが実装されていない)場合、比較器(すなわち、クラスに関するComparatorインタフェース実装クラス)を確立することによってソートを行うことができる.比較器は、上記のcompare(T o1, T o2)の方法と同様の原理を有する方法o1.compareTo(o2)を実装する必要があり、ここでは説明しない.
    両者のつながりComparableインタフェースは、内部比較器に相当するデフォルトのソートを表す自己クラスで実装される.Comparatorインタフェースは、外部比較器に相当するクラス外で実現される比較器である.
    事例の理解を深める
    比較用カスタムStudentクラス:
    public class Student implements Comparable<Student> {
         
        private String name;
        private int grade;
    
        public Student() {
         }
        
        public Student(String name, int grade) {
         
            this.name = name;
            this.grade = grade;
        }
    
        public void setName(String name) {
         
            this.name = name;
        }
    
        public void setGrade(int grade) {
         
            this.grade = grade;
        }
    
        public String getName() {
         
            return name;
        }
    
        public int getGrade() {
         
            return grade;
        }
    
        @Override
        public String toString() {
         
            return "Student{" +
                    "name='" + name + '\'' +
                    ", grade=" + grade +
                    '}';
        }
    
        @Override
        @Override
        public int compareTo(Student o) {
         
            return this.getGrade() > o.getGrade() ? 1 : this.getGrade() < o.getGrade() ? -1 : this.getName().compareTo(o.getName());
        }
    }
    

    上記のStudentクラスはComparableインタフェースを実現し、デフォルトのソートがあり、デバッグコードは以下の通りである.
    public class Main {
         
        public static void main(String[] args) {
         
            List<Student> arr = new ArrayList<>();
            arr.add(new Student("John", 100));
            arr.add(new Student("Bob", 75));
            arr.add(new Student("Alice", 100));
            arr.add(new Student("Jake", 90));
            System.out.println(arr);
            System.out.println("------------------------");
            Collections.sort(arr);  //    
            System.out.println(arr);
            
        }
    }
    
    Compartorインタフェースを実装する別の比較器は、以下のように定義される.
    public class StuCompartor implements Comparator<Student> {
         
        @Override
        public int compare(Student o1, Student o2) {
         
            return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
        }
    }
    

    デバッグコード:
    public class StuMain {
         
        public static void main(String[] args) {
         
            List<Student> arr = new ArrayList<>();
            arr.add(new Student("John", 100));
            arr.add(new Student("Bob", 75));
            arr.add(new Student("Alice", 100));
            arr.add(new Student("Jake", 90));
            System.out.println(arr);
            System.out.println("------------------------");
            Collections.sort(arr, new StuCompartor());//     
            System.out.println(arr);
        }
    }
    

    実行結果は次のとおりです.
    [Student{
         name='John', grade=100}, Student{
         name='Bob', grade=75}, Student{
         name='Alice', grade=100}, Student{
         name='Jake', grade=90}]
    ------------------------
    [Student{
         name='Bob', grade=75}, Student{
         name='Jake', grade=90}, Student{
         name='Alice', grade=100}, Student{
         name='John', grade=100}]
    

    拡張
    一度だけソートする場合は、コンパレータを定義せずに匿名の内部クラスを直接使用できます.
    Collections.sort(arr, new Comparator<Student>() {
         
        @Override
        public int compare(Student o1, Student o2) {
         
            return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
        }
    });
    

    上記の書き方は依然として煩雑で複雑であることは明らかであり、Lambda式を利用して簡略化することができる.
    Collections.sort(arr, (Student o1, Student o2) -> {
         
        return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
    });
    

    さらに簡略化(パラメータタイプを削除):
    Collections.sort(arr, (o1, o2) -> {
         
        return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
    });
    

    最終的に方法を適用して簡略化する(同時に優先比較量が等しい場合の継続比較根拠を定義する):
    Collections.sort(arr, comparing(Student::getGrade)
    			.thenComparing(Student::getName));
    

    逆順序が必要な場合は、次の手順に従います.
    Collections.sort(arr, comparing(Student::getGrade)
    			.reversed()
    			.thenComparing(Student::getName));