カスタム順序付けのための Comparator の使用
Comparable インターフェースはクラスの自然な順序を提供しますが、場合によっては、さまざまな基準に基づいてオブジェクトを異なる方法で並べ替える必要があります。ここで、Comparator インターフェースが役立ちます。
Comparator インターフェースの理解
Comparator<T> インターフェースは、同じ型の 2 つのオブジェクトを比較するメソッド compare(T o1, T o2) を定義します。比較されるクラスによって実装される Comparable とは異なり、Comparator は、さまざまな順序付け基準を定義できる別のクラスまたはラムダ式です。
カスタム Comparator の作成
Student クラスのいくつかの Comparator を作成しましょう。
NameComparator: 学生を名前で並べ替えます (アルファベット順)
AgeComparator: 学生を年齢で並べ替えます (昇順)
GradeComparator: 学生を成績で並べ替えます (降順)
次の内容で、StudentComparators.java という新しいファイルを作成します。
import java.util.Comparator;
public class StudentComparators {
// Comparator for sorting students by name
public static class NameComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return s1.getName().compareTo(s2.getName());
}
}
// Comparator for sorting students by age
public static class AgeComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return Integer.compare(s1.getAge(), s2.getAge());
}
}
// Comparator for sorting students by grade (descending)
public static class GradeComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return Double.compare(s2.getGrade(), s1.getGrade());
}
}
// Multi-attribute comparator: sort by grade (descending), then by name (alphabetically)
public static class GradeNameComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
// First compare by grade (descending)
int gradeComparison = Double.compare(s2.getGrade(), s1.getGrade());
if (gradeComparison != 0) {
return gradeComparison;
}
// If grades are equal, compare by name (alphabetically)
return s1.getName().compareTo(s2.getName());
}
}
}
Comparator のテスト
次に、これらの Comparator を使用する方法を示すテストクラスを作成しましょう。ComparatorTest.java という名前のファイルを作成します。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Comparator;
public class ComparatorTest {
public static void main(String[] args) {
// Create a list of students
List<Student> students = new ArrayList<>();
students.add(new Student("Alice", 20, 85.5));
students.add(new Student("Bob", 22, 90.0));
students.add(new Student("Charlie", 19, 78.3));
students.add(new Student("David", 21, 85.5));
students.add(new Student("Eve", 20, 92.7));
// Display original list
System.out.println("Original list of students:");
printStudents(students);
// Sort by name using NameComparator
Collections.sort(students, new StudentComparators.NameComparator());
System.out.println("\nStudents sorted by name:");
printStudents(students);
// Sort by age using AgeComparator
Collections.sort(students, new StudentComparators.AgeComparator());
System.out.println("\nStudents sorted by age (ascending):");
printStudents(students);
// Sort by grade using GradeComparator
Collections.sort(students, new StudentComparators.GradeComparator());
System.out.println("\nStudents sorted by grade (descending):");
printStudents(students);
// Sort by grade, then by name using GradeNameComparator
Collections.sort(students, new StudentComparators.GradeNameComparator());
System.out.println("\nStudents sorted by grade (descending), then by name:");
printStudents(students);
// Using Java 8 lambda expressions for comparators
System.out.println("\nUsing Java 8 lambda expressions:");
// Sort by name (alphabetically) using lambda
Collections.sort(students, (s1, s2) -> s1.getName().compareTo(s2.getName()));
System.out.println("\nStudents sorted by name (using lambda):");
printStudents(students);
// Sort by age (descending) using lambda
Collections.sort(students, (s1, s2) -> Integer.compare(s2.getAge(), s1.getAge()));
System.out.println("\nStudents sorted by age (descending, using lambda):");
printStudents(students);
// Using Comparator.comparing method
System.out.println("\nUsing Comparator.comparing method:");
// Sort by name
Collections.sort(students, Comparator.comparing(Student::getName));
System.out.println("\nStudents sorted by name (using Comparator.comparing):");
printStudents(students);
// Sort by grade (descending), then by age (ascending), then by name
Collections.sort(students,
Comparator.comparing(Student::getGrade, Comparator.reverseOrder())
.thenComparing(Student::getAge)
.thenComparing(Student::getName));
System.out.println("\nStudents sorted by grade (desc), then age (asc), then name:");
printStudents(students);
}
// Helper method to print the list of students
private static void printStudents(List<Student> students) {
for (Student student : students) {
System.out.println(student);
}
}
}
コンパイルと実行
コードをコンパイルして実行しましょう。
javac Student.java StudentComparators.java ComparatorTest.java
java ComparatorTest
出力は、さまざまな Comparator が学生の並べ替え順序にどのように影響するかを示します。
Original list of students:
Student{name='Alice', age=20, grade=85.5}
Student{name='Bob', age=22, grade=90.0}
Student{name='Charlie', age=19, grade=78.3}
Student{name='David', age=21, grade=85.5}
Student{name='Eve', age=20, grade=92.7}
Students sorted by name:
Student{name='Alice', age=20, grade=85.5}
Student{name='Bob', age=22, grade=90.0}
Student{name='Charlie', age=19, grade=78.3}
Student{name='David', age=21, grade=85.5}
Student{name='Eve', age=20, grade=92.7}
... (and so on for the other sorting methods)
Comparable と Comparator の主な違い
Comparable と Comparator の違いを理解することが重要です。
-
実装場所:
Comparable はクラス自体によって実装されます。
Comparator は、別のクラスまたはラムダ式で実装されます。
-
順序付けの数:
Comparable は、クラスの単一の「自然な順序」を定義します。
Comparator は、複数の異なる順序付けを許可します。
-
メソッドシグネチャ:
Comparable には int compareTo(T o) があります
Comparator には int compare(T o1, T o2) があります
-
使用法:
- 明らかな自然な順序がある場合、
Comparable はより簡単です。
- 複数の順序付けが必要な場合、
Comparator はより柔軟です。
最後のステップでは、Comparable と Comparator の両方を使用して学生データベースを管理する、実際のアプリケーションを作成します。