Set: HashSet, TreeSet, LinkedHashSet
Set, tekrarsız (unique) eleman tutan bir koleksiyon. Aynı elemanı iki kere ekleyemezsin. List'ten en büyük farkı bu — Set'te duplicate yok.
Bunu bir oy sandığı gibi düşün. Her kişi sadece bir kez oy verebilir. İkinci kez gelirse oyunu kabul etmezsin. Set tam olarak bu mantıkta çalışır.
Set Interface Temelleri
Set<String> colors = new HashSet<>();
colors.add("Kırmızı");
colors.add("Mavi");
colors.add("Yeşil");
colors.add("Kırmızı"); // Eklenmez! Zaten var.
System.out.println(colors.size()); // 3 — Kırmızı bir kere
System.out.println(colors); // Sıra GARANTİSİZ: [Mavi, Kırmızı, Yeşil] veya farklıSet'te index yok. set.get(0) diye bir method yok. Sıralama garantisi de implementasyona bağlı.
Set<Integer> numbers = new HashSet<>();
numbers.add(5);
numbers.add(3);
numbers.add(8);
// Temel operasyonlar
numbers.contains(3); // true — arama çok hızlı O(1)
numbers.remove(5); // true — silindi
numbers.size(); // 2
numbers.isEmpty(); // false
// Gezinme
for (int n : numbers) {
System.out.println(n);
}
// Stream ile
numbers.forEach(System.out::println);HashSet: En Hızlı Set
HashSet, arka planda HashMap kullanır. Elemanları hash tablosunda saklar. Ekleme, silme, arama — hepsi ortalama O(1).
Set<String> emails = new HashSet<>();
emails.add("ali@test.com");
emails.add("veli@test.com");
emails.add("ali@test.com"); // false döner — duplicate
System.out.println(emails.contains("ali@test.com")); // true — O(1)HashSet nasıl çalışır:
hashCode()ile elemanın hash değeri hesaplanırBu değer bir "bucket" (kova) index'ine dönüştürülür
Aynı bucket'a düşen elemanlar
equals()ile karşılaştırılırEğer
equals()true döndürürse → duplicate, eklenmez
Bu yüzden hashCode() ve equals() Set'in düzgün çalışması için hayati önemde.
hashCode() ve equals() — Set'in Kalbi
Kendi sınıflarını Set'te kullanırsan, hashCode() ve equals() override etmek zorunlu.
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
// equals override etmezsen — referans karşılaştırması yapar
// Aynı id'li iki Student farklı sayılır!
}
// SORUN
Set<Student> students = new HashSet<>();
students.add(new Student(1, "Ali"));
students.add(new Student(1, "Ali")); // İkisi de eklenir! Çünkü farklı nesneler.
System.out.println(students.size()); // 2 — yanlış!Çözüm: equals() ve hashCode() override et.
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return id == student.id && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
// ŞİMDİ DOĞRU
Set<Student> students = new HashSet<>();
students.add(new Student(1, "Ali"));
students.add(new Student(1, "Ali")); // Eklenmez! equals() true döner.
System.out.println(students.size()); // 1 — doğru!⚠️ Kritik Kural:
equals()true dönen iki nesneninhashCode()değerleri aynı olmalı. Aksi halde HashSet düzgün çalışmaz — eleman farklı bucket'a düşer ve duplicate oluşur.
// KONTRAT:
// a.equals(b) == true → a.hashCode() == b.hashCode() (ZORUNLU)
// a.hashCode() == b.hashCode() → a.equals(b) ? (Zorunlu değil — collision olabilir)TreeSet: Sıralı Set
TreeSet, elemanları doğal sırada (natural ordering) veya verdiğin Comparator'a göre sıralı tutar. Arka planda kırmızı-siyah ağaç (Red-Black Tree) kullanır.
Set<Integer> sorted = new TreeSet<>();
sorted.add(5);
sorted.add(2);
sorted.add(8);
sorted.add(1);
System.out.println(sorted); // [1, 2, 5, 8] — her zaman sıralı
Set<String> names = new TreeSet<>();
names.add("Zeynep");
names.add("Ali");
names.add("Mehmet");
System.out.println(names); // [Ali, Mehmet, Zeynep] — alfabetikTreeSet performansı:
| Operasyon | Zaman |
|---|---|
add | O(log n) |
remove | O(log n) |
contains | O(log n) |
HashSet'ten yavaş (O(1) vs O(log n)) ama sıralama garantisi var.
// Custom sıralama ile TreeSet
Set<String> byLength = new TreeSet<>(Comparator.comparingInt(String::length));
byLength.add("Java");
byLength.add("C");
byLength.add("Python");
byLength.add("Go");
System.out.println(byLength); // [C, Go, Java, Python] — uzunluğa göre
// DİKKAT: Aynı uzunluktaki elemanlar duplicate sayılır!
byLength.add("JS"); // "Go" ile aynı uzunluk — eklenmez!⚠️ TreeSet Tuzağı: TreeSet, eşitliği
compareTo()(veya Comparator) ile belirler,equals()ile değil. Comparator 0 döndürürse eleman duplicate sayılır ve eklenmez.
// TreeSet'e kendi sınıfını koymak — Comparable zorunlu (veya Comparator ver)
public class Student implements Comparable<Student> {
private String name;
@Override
public int compareTo(Student other) {
return this.name.compareTo(other.name);
}
}
// Comparable implement etmeyen sınıf → ClassCastException
Set<MyClass> set = new TreeSet<>();
set.add(new MyClass()); // ClassCastException!LinkedHashSet: Ekleme Sırasını Koruyan Set
LinkedHashSet, HashSet gibi çalışır ama ek olarak ekleme sırasını korur. Arka planda hash tablosu + çift yönlü bağlı liste kullanır.
Set<String> linked = new LinkedHashSet<>();
linked.add("Üçüncü");
linked.add("Birinci");
linked.add("İkinci");
linked.add("Birinci"); // Duplicate — eklenmez
System.out.println(linked); // [Üçüncü, Birinci, İkinci] — ekleme sırası korunur
// HashSet ile karşılaştır
Set<String> hash = new HashSet<>(linked);
System.out.println(hash); // Sıra belirsiz — [İkinci, Birinci, Üçüncü] olabilirLinkedHashSet, HashSet'ten biraz daha fazla bellek kullanır (linked list referansları yüzünden) ama sıralama garantisi verir.
Üçü Arasındaki Fark
| Özellik | HashSet | TreeSet | LinkedHashSet |
|---|---|---|---|
| Sıralama | Yok | Doğal/Custom | Ekleme sırası |
| add/remove/contains | O(1) | O(log n) | O(1) |
| null eleman | 1 tane OK | ❌ (NullPointerException) | 1 tane OK |
| Arka plan | HashMap | Red-Black Tree | HashMap + LinkedList |
| Bellek | En az | Orta | En fazla |
Ne zaman hangisi:
// Sadece unique'lik lazım, sıra önemli değil → HashSet
Set<String> visited = new HashSet<>();
// Sıralı unique elemanlar lazım → TreeSet
Set<Integer> sortedScores = new TreeSet<>();
// Ekleme sırasını korumak lazım → LinkedHashSet
Set<String> insertionOrder = new LinkedHashSet<>();Küme Operasyonları
Set'in en güçlü yanlarından biri: matematiksel küme operasyonları.
Set<Integer> a = new HashSet<>(Set.of(1, 2, 3, 4, 5));
Set<Integer> b = new HashSet<>(Set.of(4, 5, 6, 7, 8));
// BİRLEŞİM (Union): A ∪ B
Set<Integer> union = new HashSet<>(a);
union.addAll(b);
System.out.println(union); // [1, 2, 3, 4, 5, 6, 7, 8]
// KESİŞİM (Intersection): A ∩ B
Set<Integer> intersection = new HashSet<>(a);
intersection.retainAll(b);
System.out.println(intersection); // [4, 5]
// FARK (Difference): A - B
Set<Integer> difference = new HashSet<>(a);
difference.removeAll(b);
System.out.println(difference); // [1, 2, 3]
// SİMETRİK FARK: (A ∪ B) - (A ∩ B)
Set<Integer> symmetric = new HashSet<>(a);
symmetric.addAll(b);
Set<Integer> common = new HashSet<>(a);
common.retainAll(b);
symmetric.removeAll(common);
System.out.println(symmetric); // [1, 2, 3, 6, 7, 8]Set.of() — Immutable Set (Java 9+)
Set<String> immutable = Set.of("A", "B", "C");
// immutable.add("D"); // UnsupportedOperationException!
// DİKKAT: duplicate veremezsin
// Set.of("A", "A"); // IllegalArgumentException!
// null veremezsin
// Set.of(null); // NullPointerException!Gerçek Dünya: Duplicate Temizleme
// List'ten duplicate'leri temizlemenin en kolay yolu
List<String> withDuplicates = List.of("Ali", "Veli", "Ali", "Can", "Veli");
List<String> unique = new ArrayList<>(new LinkedHashSet<>(withDuplicates));
System.out.println(unique); // [Ali, Veli, Can] — sıra korundu, duplicate gitti
// Stream ile
List<String> unique2 = withDuplicates.stream()
.distinct()
.collect(Collectors.toList());💡 İpucu: Duplicate temizlerken sırayı korumak istiyorsan
LinkedHashSetkullan. Sıra önemli değilseHashSetyeterli.
Özet
Set tekrarsız (unique) eleman tutar —
add()duplicate'i reddederHashSet en hızlı (O(1)) ama sıra garantisi yok —
hashCode()veequals()doğru override edilmeliTreeSet elemanları sıralı tutar (O(log n)) — Comparable veya Comparator gerektirir, null kabul etmez
LinkedHashSet ekleme sırasını korur, HashSet kadar hızlı, biraz daha fazla bellek kullanır
hashCode/equals kontratı kritik:
equals()true isehashCode()aynı olmalı — aksi halde Set bozulurKüme operasyonları (birleşim, kesişim, fark)
addAll,retainAll,removeAllile yapılır
AI Asistan
Sorularını yanıtlamaya hazır