Comparator Interface
Nesneleri sıralamak programlamanın en temel ihtiyaçlarından biri. Sayıları küçükten büyüğe, isimleri alfabetik, tarihleri eskiden yeniye, ürünleri fiyata göre... Java'da bu sıralamanın iki yolu var: Comparable ve Comparator.
Analoji: Bir yarışma düzenliyorsun. Comparable, yarışmacının kendi üzerinde taşıdığı numara — "doğal sıram bu." Comparator ise jüri — dışarıdan bakıp "şu kritere göre sıralayalım" diyen kişi. Yarışmacı değişmez ama jüri kriterleri her seferinde farklı olabilir.
Comparable: Doğal Sıralama
Comparable<T> interface'i, sınıfın kendi doğal sırasını tanımlar. Tek bir method'u var: compareTo().
public class Student implements Comparable<Student> {
private String name;
private double gpa;
public Student(String name, double gpa) {
this.name = name;
this.gpa = gpa;
}
@Override
public int compareTo(Student other) {
// Negatif: this < other
// Sıfır: this == other
// Pozitif: this > other
return this.name.compareTo(other.name); // İsme göre doğal sıra
}
@Override
public String toString() {
return name + "(" + gpa + ")";
}
}List<Student> students = new ArrayList<>(List.of(
new Student("Zeynep", 3.8),
new Student("Ali", 3.5),
new Student("Mehmet", 3.9)
));
Collections.sort(students); // compareTo() kullanılır
System.out.println(students); // [Ali(3.5), Mehmet(3.9), Zeynep(3.8)]Java'daki birçok sınıf zaten Comparable'dır:
String→ alfabetikInteger,Double→ sayısalLocalDate,LocalDateTime→ kronolojikBigDecimal→ sayısal
// String'ler zaten Comparable
List<String> names = new ArrayList<>(List.of("Zeynep", "Ali", "Can"));
Collections.sort(names); // [Ali, Can, Zeynep]
// Integer'lar da
List<Integer> nums = new ArrayList<>(List.of(5, 2, 8, 1));
Collections.sort(nums); // [1, 2, 5, 8]compareTo() Kuralları
// compareTo kontratı:
// 1. sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) (simetri)
// 2. x.compareTo(y) > 0 && y.compareTo(z) > 0 → x.compareTo(z) > 0 (geçişlilik)
// 3. x.compareTo(y) == 0 → sgn(x.compareTo(z)) == sgn(y.compareTo(z))
// 4. İdeal: (x.compareTo(y) == 0) == x.equals(y) (tutarlılık)⚠️ Dikkat:
compareTo()ile çıkarma yapmak (return this.age - other.age) integer overflow'a neden olabilir.Integer.compare()kullan.
// HATALI — overflow riski
public int compareTo(Student other) {
return this.age - other.age; // Integer.MIN_VALUE - 1 = ???
}
// DOĞRU
public int compareTo(Student other) {
return Integer.compare(this.age, other.age);
}Comparator: Dışarıdan Sıralama
Comparator<T> interface'i, sıralama mantığını sınıfın dışında tanımlar. Aynı koleksiyonu farklı kriterlere göre sıralayabilirsin.
List<Student> students = getStudents();
// İsme göre sırala
students.sort(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getName().compareTo(s2.getName());
}
});
// Lambda ile daha temiz (Java 8+)
students.sort((s1, s2) -> s1.getName().compareTo(s2.getName()));
// Method reference ile daha da temiz
students.sort(Comparator.comparing(Student::getName));Comparator.comparing() — Modern Yaklaşım
Java 8 ile gelen Comparator.comparing() factory method'u hayat kurtarıcı:
List<Student> students = getStudents();
// İsme göre
students.sort(Comparator.comparing(Student::getName));
// GPA'ya göre
students.sort(Comparator.comparingDouble(Student::getGpa));
// Yaşa göre
students.sort(Comparator.comparingInt(Student::getAge));
// Ters sıra
students.sort(Comparator.comparing(Student::getName).reversed());Primitive tipler için özel method'lar var:
Comparator.comparingInt()→ int field içinComparator.comparingLong()→ long field içinComparator.comparingDouble()→ double field için
Bunlar autoboxing'den kaçınır, daha performanslı.
Chained Comparators — Çoklu Kriter
Birden fazla kritere göre sıralama yapmak çok kolay:
// Önce GPA'ya göre (azalan), eşitse isme göre (artan)
students.sort(
Comparator.comparingDouble(Student::getGpa).reversed()
.thenComparing(Student::getName)
);
// Önce departman, sonra yaş, sonra isim
employees.sort(
Comparator.comparing(Employee::getDepartment)
.thenComparingInt(Employee::getAge)
.thenComparing(Employee::getName)
);thenComparing() zinciri: önceki kriter eşitlik verdiğinde bir sonraki kritere geçer. SQL'deki ORDER BY dept, age, name gibi.
// Örnek: Ürünleri önce kategoriye, sonra fiyata, sonra isme göre sırala
List<Product> products = getProducts();
products.sort(
Comparator.comparing(Product::getCategory)
.thenComparingDouble(Product::getPrice)
.thenComparing(Product::getName)
);null Handling
null değerler sıralama sırasında NullPointerException verebilir. Comparator.nullsFirst() ve nullsLast() bunu çözer:
List<String> names = new ArrayList<>(Arrays.asList("Ali", null, "Zeynep", null, "Can"));
// null'ları başa koy
names.sort(Comparator.nullsFirst(Comparator.naturalOrder()));
// [null, null, Ali, Can, Zeynep]
// null'ları sona koy
names.sort(Comparator.nullsLast(Comparator.naturalOrder()));
// [Ali, Can, Zeynep, null, null]
// Nesne field'ı null olabilir
students.sort(
Comparator.comparing(
Student::getDepartment,
Comparator.nullsLast(Comparator.naturalOrder())
)
);Comparable vs Comparator
| Özellik | Comparable | Comparator |
|---|---|---|
| Interface | java.lang.Comparable | java.util.Comparator |
| Method | compareTo(T o) | compare(T o1, T o2) |
| Tanım yeri | Sınıfın içinde | Sınıfın dışında |
| Sıralama sayısı | Tek (doğal sıra) | İstediğin kadar |
| Sınıfı değiştirmek | Gerekir | Gerekmez |
| Kullanım | Collections.sort(list) | Collections.sort(list, comp) |
// Comparable — sınıfın doğal sırası
public class Temperature implements Comparable<Temperature> {
private double celsius;
@Override
public int compareTo(Temperature other) {
return Double.compare(this.celsius, other.celsius);
}
}
// Comparator — farklı sıralama kriterleri
Comparator<Temperature> byCelsius = Comparator.comparingDouble(Temperature::getCelsius);
Comparator<Temperature> byFahrenheit = Comparator.comparingDouble(Temperature::getFahrenheit);💡 İpucu: Sınıfın tek bir "doğal" sırası varsa (sayılar → büyüklük, tarihler → kronoloji)
Comparableimplement et. Birden fazla sıralama kriteri gerekiyorsaComparatorkullan. İkisi birlikte de olabilir.
Comparator ve Collections/Arrays
// Collections.sort
Collections.sort(list, Comparator.reverseOrder());
// List.sort (Java 8+)
list.sort(Comparator.comparing(Student::getName));
// Stream.sorted
list.stream()
.sorted(Comparator.comparingDouble(Student::getGpa).reversed())
.collect(Collectors.toList());
// Arrays.sort
String[] arr = {"Zeynep", "Ali", "Can"};
Arrays.sort(arr, Comparator.reverseOrder());
// TreeSet / TreeMap ile
Set<Student> sorted = new TreeSet<>(Comparator.comparing(Student::getName));
Map<Student, String> map = new TreeMap<>(Comparator.comparingDouble(Student::getGpa));Gerçek Dünya: E-ticaret Ürün Sıralaması
public class ProductSorter {
public static final Comparator<Product> BY_PRICE_ASC =
Comparator.comparingDouble(Product::getPrice);
public static final Comparator<Product> BY_PRICE_DESC =
BY_PRICE_ASC.reversed();
public static final Comparator<Product> BY_RATING =
Comparator.comparingDouble(Product::getRating).reversed();
public static final Comparator<Product> BY_NAME =
Comparator.comparing(Product::getName, String.CASE_INSENSITIVE_ORDER);
public static final Comparator<Product> BY_RELEVANCE =
BY_RATING.thenComparing(BY_PRICE_ASC);
public static List<Product> sort(List<Product> products, String criteria) {
Comparator<Product> comparator = switch (criteria) {
case "price_asc" -> BY_PRICE_ASC;
case "price_desc" -> BY_PRICE_DESC;
case "rating" -> BY_RATING;
case "name" -> BY_NAME;
default -> BY_RELEVANCE;
};
return products.stream()
.sorted(comparator)
.collect(Collectors.toList());
}
}Özet
Comparable sınıfın doğal sırasını tanımlar —
compareTo()method'u, sınıfın içinde implement edilirComparator dışarıdan sıralama mantığı verir — aynı koleksiyonu farklı kriterlere göre sıralayabilirsin
Comparator.comparing()factory method'u ile lambda yazmadan temiz comparator oluşturChained comparators:
thenComparing()ile çoklu kriter — "önce X'e göre, eşitse Y'ye göre"null handling:
Comparator.nullsFirst()/nullsLast()ile NullPointerException'dan kaçınInteger karşılaştırmada çıkarma yapma (
a - b) —Integer.compare(a, b)kullan (overflow riski)
AI Asistan
Sorularını yanıtlamaya hazır