List: ArrayList ve LinkedList
List, Collections Framework'ün en çok kullanılan arayüzü. Sıralı, index'li ve duplicate'e izin veren bir koleksiyon. Elemanları ekleme sırasında tutar, her birinin bir numarası (index) vardır.
List'in iki ana implementasyonu var: ArrayList ve LinkedList. İkisi de aynı interface'i implement eder ama iç yapıları tamamen farklı. Bu da performans farklarına yol açar.
Analoji: ArrayList bir apartman gibi. Her dairenin numarası var, istediğin kata asansörle direkt gidersin. Ama kat eklemek için binanın üstüne çıkman lazım. LinkedList ise bir tren gibi. Her vagon sonrakine bağlı. Ortaya vagon eklemek kolay ama "7. vagona git" demek için baştan saymak zorundasın.
ArrayList İç Yapısı
ArrayList, arka planda bir dizi (array) kullanır. Ama normal array'den farklı olarak, dolunca otomatik büyür.
// ArrayList oluşturma
List<String> names = new ArrayList<>(); // Boş, default kapasite (10)
List<String> names2 = new ArrayList<>(50); // Başlangıç kapasitesi 50
List<String> names3 = new ArrayList<>(List.of("Ali", "Veli")); // Var olan koleksiyondanİç yapı nasıl çalışır:
Başlangıçta 10 elemanlık bir dizi oluşturulur (default capacity)
Dizi dolunca, 1.5 katı büyüklüğünde yeni dizi oluşturulur
Eski elemanlar yeni diziye kopyalanır
Bu "grow" operasyonu O(n) maliyetindedir
List<Integer> list = new ArrayList<>(4); // Kapasite: 4
list.add(1); // [1, _, _, _]
list.add(2); // [1, 2, _, _]
list.add(3); // [1, 2, 3, _]
list.add(4); // [1, 2, 3, 4] — dolu!
list.add(5); // Büyüme! Kapasite: 6 → [1, 2, 3, 4, 5, _]💡 İpucu: Eğer kaç eleman ekleyeceğini biliyorsan, başlangıç kapasitesini belirle. Bu, gereksiz büyüme (resize) operasyonlarını önler.
// 10.000 eleman ekleyeceğini biliyorsan
List<String> bigList = new ArrayList<>(10000);
// Kapasite 10 → 15 → 22 → ... → 10000 yerine direkt 10000 başlarArrayList Temel Operasyonlar
List<String> fruits = new ArrayList<>();
// Ekleme
fruits.add("Elma"); // Sona ekle
fruits.add(0, "Muz"); // Index 0'a ekle (kaydırma gerekir)
fruits.addAll(List.of("Portakal", "Üzüm")); // Toplu ekle
// Erişim
String first = fruits.get(0); // Index ile erişim — O(1)
int index = fruits.indexOf("Elma"); // İlk bulduğu index
int last = fruits.lastIndexOf("Elma"); // Son bulduğu index
// Güncelleme
fruits.set(1, "Kivi"); // Index 1'deki elemanı değiştir
// Silme
fruits.remove("Muz"); // Değere göre sil (ilk eşleşen)
fruits.remove(0); // Index'e göre sil
fruits.removeIf(f -> f.startsWith("P")); // Koşula göre sil
// Diğer
int size = fruits.size(); // Eleman sayısı
boolean has = fruits.contains("Kivi"); // İçeriyor mu?
fruits.clear(); // Hepsini sil⚠️ Integer listede remove karışıklığı:
remove(int index)veremove(Object o)çakışır.list.remove(3)index mi yoksa değer mi?
List<Integer> nums = new ArrayList<>(List.of(10, 20, 30));
nums.remove(1); // INDEX 1'deki elemanı siler → [10, 30]
nums.remove(Integer.valueOf(10)); // DEĞER 10'u siler → [30]ArrayList Performans
| Operasyon | Zaman | Açıklama |
|---|---|---|
get(index) | O(1) | Direkt erişim — en güçlü yanı |
add(eleman) | O(1)* | Sona ekleme (*amortized — resize olursa O(n)) |
add(index, eleman) | O(n) | Ortaya ekleme — elemanları kaydırmak gerekir |
remove(index) | O(n) | Ortadan silme — elemanları kaydırmak gerekir |
contains(eleman) | O(n) | Baştan sona arama |
indexOf(eleman) | O(n) | Baştan sona arama |
ArrayList'in gücü: random access (index ile erişim). Zayıf noktası: ortaya ekleme/silme.
LinkedList İç Yapısı
LinkedList, çift yönlü bağlı liste (doubly linked list) kullanır. Her eleman (node) üç şey tutar: değer, önceki node'un referansı, sonraki node'un referansı.
null ← [Elma] ⇄ [Armut] ⇄ [Muz] → null
head tailList<String> linked = new LinkedList<>();
linked.add("Elma");
linked.add("Armut");
linked.add("Muz");
// LinkedList'e özel method'lar (Deque interface'inden)
LinkedList<String> ll = new LinkedList<>(List.of("A", "B", "C"));
ll.addFirst("X"); // Başa ekle
ll.addLast("Z"); // Sona ekle
String first = ll.getFirst(); // İlk eleman
String last = ll.getLast(); // Son eleman
ll.removeFirst(); // Baştan sil
ll.removeLast(); // Sondan silLinkedList Performans
| Operasyon | Zaman | Açıklama |
|---|---|---|
get(index) | O(n) | Baştan veya sondan sayarak ilerlemek gerekir |
add(eleman) | O(1) | Sona ekleme — tail pointer'ı güncelle |
addFirst(eleman) | O(1) | Başa ekleme — head pointer'ı güncelle |
add(index, eleman) | O(n) | Index'e ulaşmak O(n), ekleme O(1) |
remove(index) | O(n) | Index'e ulaşmak O(n), silme O(1) |
contains(eleman) | O(n) | Baştan sona arama |
LinkedList'in gücü: başa/sona ekleme-silme O(1). Zayıf noktası: index ile erişim O(n).
ArrayList vs LinkedList: Ne Zaman Hangisi?
// SENARYO 1: Çok okuma, az yazma → ArrayList
// Örn: Ürün listesi görüntüleme
List<Product> products = new ArrayList<>();
// products.get(42) → O(1), süper hızlı
// SENARYO 2: Sürekli başa/sona ekleme-silme → LinkedList
// Örn: Mesaj kuyruğu
LinkedList<Message> queue = new LinkedList<>();
queue.addLast(newMessage); // O(1)
queue.removeFirst(); // O(1)
// SENARYO 3: Ortadan çok silme → Hiçbiri mükemmel değil
// ArrayList: silme O(n), ama cache-friendly
// LinkedList: node'a ulaşmak O(n), silme O(1)
// Pratikte: ArrayList genelde yine kazanır (CPU cache etkisi)💡 Gerçek: Pratikte neredeyse her zaman ArrayList kullan. LinkedList'in teorik avantajı, modern CPU'ların cache yapısı nedeniyle genellikle gerçekleşmez. LinkedList'i sadece Queue/Deque olarak kullanırken tercih et.
SubList
List'in bir bölümünü "view" olarak alabilirsin:
List<Integer> nums = new ArrayList<>(List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
List<Integer> sub = nums.subList(2, 6); // [2, 3, 4, 5] — index 2 dahil, 6 hariç
System.out.println(sub);
sub.set(0, 99); // sub'ı değiştirmek orijinali de değiştirir!
System.out.println(nums); // [0, 1, 99, 3, 4, 5, 6, 7, 8, 9]
sub.clear(); // sub'ı temizlemek orijinalden de siler
System.out.println(nums); // [0, 1, 5, 6, 7, 8, 9]subList bir kopya değil, görünüm (view). Değişiklikler orijinal listeye yansır.
Sıralama
List<String> names = new ArrayList<>(List.of("Zeynep", "Ali", "Mehmet", "Canan"));
// Doğal sıralama (Comparable)
Collections.sort(names); // [Ali, Canan, Mehmet, Zeynep]
names.sort(null); // Aynı şey
names.sort(Comparator.naturalOrder()); // Aynı şey
// Ters sıralama
names.sort(Comparator.reverseOrder()); // [Zeynep, Mehmet, Canan, Ali]
// Özel sıralama — uzunluğa göre
names.sort(Comparator.comparingInt(String::length));
// [Ali, Canan, Zeynep, Mehmet]
// Sayılar
List<Integer> nums = new ArrayList<>(List.of(5, 2, 8, 1, 9));
Collections.sort(nums); // [1, 2, 5, 8, 9]List.of() ve List.copyOf() — Immutable Listeler
// List.of() — değiştirilemez liste (Java 9+)
List<String> immutable = List.of("A", "B", "C");
// immutable.add("D"); // UnsupportedOperationException!
// immutable.set(0, "X"); // UnsupportedOperationException!
// immutable.remove(0); // UnsupportedOperationException!
// List.copyOf() — var olan listeyi kopyalayarak immutable yap (Java 10+)
List<String> original = new ArrayList<>(List.of("X", "Y"));
List<String> copy = List.copyOf(original);
original.add("Z"); // copy ETKİLENMEZ
// Arrays.asList() — sabit boyutlu ama değiştirilebilir
List<String> fixed = Arrays.asList("A", "B", "C");
fixed.set(0, "X"); // OK — eleman değiştirme
// fixed.add("D"); // UnsupportedOperationException! — boyut değişmez| Method | Değiştirilebilir mi? | Boyut değişir mi? | null izin? |
|---|---|---|---|
new ArrayList<>() | ✅ | ✅ | ✅ |
Arrays.asList() | ✅ (set) | ❌ (add/remove) | ✅ |
List.of() | ❌ | ❌ | ❌ |
List.copyOf() | ❌ | ❌ | ❌ |
Collections.unmodifiableList() | ❌ | ❌ | ✅ |
List ile Yaygın Pattern'lar
// Filtreleme (Java 8+ Stream)
List<String> longNames = names.stream()
.filter(n -> n.length() > 3)
.collect(Collectors.toList());
// Dönüştürme
List<Integer> lengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
// Birleştirme
String joined = String.join(", ", names); // "Ali, Veli, Ahmet"
// Kopyalama
List<String> copy = new ArrayList<>(original); // Shallow copy
// Boş liste kontrolü
if (list != null && !list.isEmpty()) {
// Güvenli
}Özet
ArrayList arka planda dizi kullanır —
get(index)O(1) ile en güçlü yönü, ortadan ekleme/silme O(n) ile zayıf yönüLinkedList çift yönlü bağlı liste — başa/sona ekleme O(1), ama index erişimi O(n)
Pratikte ArrayList neredeyse her zaman tercih edilir — CPU cache etkisi LinkedList'in teorik avantajını siler
List.of()veList.copyOf()ile immutable listeler oluşturabilirsin (Java 9+/10+)Integer listede
remove()karışıklığına dikkat —remove(1)index'tir,remove(Integer.valueOf(1))değerdirDeğişkeni
List<>tipinde tanımla, implementasyonu (ArrayList/LinkedList) sağ tarafta seç — esneklik sağlar
AI Asistan
Sorularını yanıtlamaya hazır