Comparator (Esnek ve Çoklu Sıralama)
Comparable bir tipe tek bir doğal sıra kazandırır. Ama gerçek hayatta aynı veriyi farklı zamanlarda farklı ölçütlere göre sıralamak isteriz: ürünleri kâh fiyata, kâh ada, kâh stoğa göre. Sınıfın içine her sıralamayı y…
Comparator (Esnek ve Çoklu Sıralama)
Comparable bir tipe tek bir doğal sıra kazandırır. Ama gerçek hayatta aynı veriyi farklı
zamanlarda farklı ölçütlere göre sıralamak isteriz: ürünleri kâh fiyata, kâh ada, kâh stoğa göre.
Sınıfın içine her sıralamayı yazmak mümkün değil. İşte Comparator tam da bunun içindir:
sıralama mantığını sınıfın dışında, ayrı bir nesne olarak tanımlar; böylece aynı tip için
istediğin kadar alternatif sıra üretirsin — hiç sınıfı değiştirmeden.
compare: iki nesneyi karşılaştır
Comparator<T> tek soyut metot ister: int compare(T a, T b) — dönüş işareti compareTo ile
aynı kuralı izler (negatif a<b, 0 eşit, pozitif a>b). Functional interface olduğu için
lambda ile yazılır. Ama asıl güç, hazır fabrika metotlarındadır:
Comparator.comparing(Urun::ad) // ada göre Comparator.comparingDouble(Urun::fiyat) // fiyata göre (primitive, kutulamasız) Comparator.comparingDouble(Urun::fiyat).reversed() // azalan
Örnek 1 (./Ornek1.java) aynı ürün listesini ada, fiyata (artan/azalan) ve stoğa göre sıralar —
hepsi sınıfı değiştirmeden.
Çok seviyeli sıralama: thenComparing
Birden çok ölçüt gerektiğinde thenComparing ile zincir kurarsın: ilk ölçüt eşitse ikinciye
geçilir. Her seviyeyi ayrı ayrı ters çevirebilirsin:
Comparator<Calisan> sira = Comparator .comparing(Calisan::departman) // 1) departman ↑ .thenComparing(Comparator.comparingInt(Calisan::maas).reversed()) // 2) maaş ↓ .thenComparing(Calisan::ad); // 3) ad ↑
Örnek 2 (./Ornek2.java) bunu ve null güvenliğini gösterir: nullsFirst/nullsLast, null
içeren listelerde NullPointerException'ı önler; naturalOrder()/reverseOrder() hazır sıralardır.
Comparable ile birlikte
İkisi birbirini tamamlar:
Comparable→ tipin varsayılan sırası.stream.sorted()(argümansız) veCollections.sort(list)bunu kullanır.Comparator→ o anki ihtiyaca göre varsayılanı ezen esnek sıra.stream.sorted(cmp),list.sort(cmp)veTreeSet/TreeMapyapıcısına verilir.
Örnek 3 (./Ornek3.java) puana göre doğal sıralı bir Oyuncu tanımlar, sonra bir Comparator'la
"puan ↓, süre ↑" liderlik sırasına geçer ve TreeMap'e özel sıra verir.
Nerede kullanılır?
- Stream:
.sorted(comparator)— veri işleme hatlarında. - Koleksiyonlar:
list.sort(cmp),TreeSet/TreeMap(cmp ver),PriorityQueue(öncelik sırası). - min/max:
list.stream().max(Comparator.comparing(...)). - Gruplama sonrası: rapor/tablo sıralamaları (en çok satan, en yeni...).
| Comparable | Comparator | |
|---|---|---|
| Nerede | Sınıfın içinde (compareTo) | Sınıfın dışında (ayrı nesne) |
| Kaç sıra | Tek (doğal) | Sınırsız (alternatif) |
| Sınıfı değiştirir mi | Evet | Hayır |
| Tipik | Varsayılan sıra | Özel/çoklu sıra |
Özet
Comparator ile sınıfı değiştirmeden esnek ve çoklu sıralamayı: fabrika metotlarını
(comparing/comparingInt/reversed) (Örnek 1); çok seviyeli thenComparing ve null güvenliğini
(Örnek 2); Comparable ile birlikte stream/TreeMap kullanımını (Örnek 3) öğrendik. "Tek doğal sıra
→ Comparable, çok/özel sıra → Comparator" kuralı işini görür. Sırada, Iterator'ın atası ve eski
koleksiyonlar: Enumeration ve legacy yapılar.
▶ Kod Örnekleri(3)
Ornek1
çalıştırılabilir1// Ornek1: Comparator — sınıfı değiştirmeden, dışarıdan farklı sıralamalar tanımlamak.
2// Çalıştırma: java Ornek1.java
3import java.util.ArrayList;
4import java.util.Comparator;
5import java.util.List;
6
7public class Ornek1 {
8
9 record Urun(String ad, double fiyat, int stok) {}
10
11 public static void main(String[] args) {
12 List<Urun> urunler = new ArrayList<>(List.of(
13 new Urun("Monitör", 3200, 5),
14 new Urun("Mouse", 250, 40),
15 new Urun("Klavye", 450, 12),
16 new Urun("Kulaklık", 900, 12)));
17
18 // Comparator dışarıdan tanımlanır; aynı listeyi farklı ölçütlerle sıralayabiliriz.
19
20 // 1) Ada göre (alfabetik) — Comparator.comparing + anahtar çıkarıcı
21 urunler.sort(Comparator.comparing(Urun::ad));
22 System.out.println("Ada göre : " + urunler.stream().map(Urun::ad).toList());
23
24 // 2) Fiyata göre artan
25 urunler.sort(Comparator.comparingDouble(Urun::fiyat));
26 System.out.println("Fiyat artan: " + urunler.stream().map(Urun::ad).toList());
27
28 // 3) Fiyata göre AZALAN — reversed()
29 urunler.sort(Comparator.comparingDouble(Urun::fiyat).reversed());
30 System.out.println("Fiyat azalan: " + urunler.stream().map(Urun::ad).toList());
31
32 // 4) Lambda ile elle: stoğa göre
33 urunler.sort((a, b) -> Integer.compare(a.stok(), b.stok()));
34 System.out.println("Stok artan : " + urunler.stream().map(Urun::ad).toList());
35
36 System.out.println("""
37
38 --- Comparator ---
39 Comparator, sıralama mantığını sınıfın DIŞINDA tutar; aynı tip için BİRDEN ÇOK sıra tanımlanır.
40 compare(a,b): negatif (a<b), 0 (eşit), pozitif (a>b).
41 Kısa yollar: Comparator.comparing(anahtar), comparingInt/Double, .reversed().
42 Sınıfı hiç değiştirmeden, ihtiyaca göre kâh ada kâh fiyata göre sıralarsın.""");
43 }
44}Ornek2
çalıştırılabilir1// Ornek2: Çok seviyeli sıralama (thenComparing) ve null güvenliği.
2// Çalıştırma: java Ornek2.java
3import java.util.ArrayList;
4import java.util.Arrays;
5import java.util.Comparator;
6import java.util.List;
7
8public class Ornek2 {
9
10 record Calisan(String departman, String ad, int maas) {}
11
12 public static void main(String[] args) {
13 List<Calisan> liste = new ArrayList<>(List.of(
14 new Calisan("Yazılım", "Ada", 50000),
15 new Calisan("Yazılım", "Burak", 60000),
16 new Calisan("Satış", "Can", 40000),
17 new Calisan("Yazılım", "Ada", 55000)));
18
19 // Çok seviyeli: önce departman (artan), eşitse maaş (AZALAN), eşitse ad.
20 Comparator<Calisan> sira = Comparator
21 .comparing(Calisan::departman)
22 .thenComparing(Comparator.comparingInt(Calisan::maas).reversed())
23 .thenComparing(Calisan::ad);
24
25 liste.sort(sira);
26 System.out.println("Departman ↑, maaş ↓, ad ↑:");
27 liste.forEach(c -> System.out.println(" " + c));
28
29 // null güvenliği: nullsFirst / nullsLast
30 List<String> adlar = new ArrayList<>(Arrays.asList("Zeynep", null, "Ahmet", null, "Berk"));
31 adlar.sort(Comparator.nullsFirst(Comparator.naturalOrder()));
32 System.out.println("\nnull'lar önce: " + adlar);
33
34 adlar.sort(Comparator.nullsLast(Comparator.reverseOrder()));
35 System.out.println("null'lar sonda, ters: " + adlar);
36
37 System.out.println("""
38
39 --- thenComparing ve null güvenliği ---
40 thenComparing: ilk ölçüt eşitse İKİNCİ ölçüte geç (zincir). İstediğin kadar seviye ekleyebilirsin.
41 Her seviyeyi ayrı ayrı .reversed() ile ters çevirebilirsin (örn. departman ↑ ama maaş ↓).
42 naturalOrder()/reverseOrder(): hazır doğal/ters sıra.
43 nullsFirst/nullsLast: null içeren listelerde NullPointerException'ı önler.""");
44 }
45}Ornek3
çalıştırılabilir1// Ornek3: Comparable + Comparator birlikte; stream.sorted ve TreeMap ile özel sıra.
2// Çalıştırma: java Ornek3.java
3import java.util.Comparator;
4import java.util.List;
5import java.util.TreeMap;
6
7public class Ornek3 {
8
9 // Sınıfın DOĞAL sırası (Comparable): puana göre azalan (liderlik tablosu mantığı).
10 record Oyuncu(String ad, int puan, int sure) implements Comparable<Oyuncu> {
11 @Override public int compareTo(Oyuncu o) { return Integer.compare(o.puan, this.puan); } // azalan
12 }
13
14 public static void main(String[] args) {
15 List<Oyuncu> oyuncular = List.of(
16 new Oyuncu("Ada", 90, 120),
17 new Oyuncu("Burak", 90, 95),
18 new Oyuncu("Can", 75, 60),
19 new Oyuncu("Derya", 88, 140));
20
21 // 1) Doğal sıra (Comparable): puan azalan — stream.sorted() argümansız.
22 System.out.println("Doğal sıra (puan ↓):");
23 oyuncular.stream().sorted().forEach(o -> System.out.println(" " + o));
24
25 // 2) Comparator ile EZ: puan azalan, eşitse süre artan (daha hızlı bitiren önde).
26 Comparator<Oyuncu> liderlik = Comparator
27 .comparingInt(Oyuncu::puan).reversed()
28 .thenComparingInt(Oyuncu::sure);
29 System.out.println("\nÖzel sıra (puan ↓, süre ↑):");
30 oyuncular.stream().sorted(liderlik).forEach(o -> System.out.println(" " + o));
31
32 // 3) TreeMap'e özel Comparator vererek anahtarları o sıraya göre tut (uzun string önce).
33 TreeMap<String, Integer> harita = new TreeMap<>(Comparator.comparingInt(String::length).reversed()
34 .thenComparing(Comparator.naturalOrder()));
35 oyuncular.forEach(o -> harita.put(o.ad(), o.puan()));
36 System.out.println("\nTreeMap (ada göre uzunluk ↓): " + harita.keySet());
37
38 System.out.println("""
39
40 --- Comparable + Comparator birlikte ---
41 Comparable: tipin tek 'varsayılan' sırası (stream.sorted() argümansız bunu kullanır).
42 Comparator: o anki ihtiyaca göre, varsayılanı EZEN esnek sıralar (stream.sorted(cmp)).
43 Comparator ayrıca TreeSet/TreeMap'e verilebilir; koleksiyon elemanlarını o sıraya göre tutar.
44 Pratik kural: tek doğal sıra -> Comparable; çok/özel sıra -> Comparator.""");
45 }
46}