kamer.dev

Java Collection Framework (Türkçe)

- #java

Merhabalar. Bu yazımda Java Collection Framework’ten bahsedeceğim. Öncelikle Oracle’ın sitesinden Java 8 Dokümanlarını inceleyelim.

java.util paketinde yer alan collection framework’ün hiyerarşik yapısını incelediğimizde en üstte karşımıza Iterable interface’i çıkar. Bu interface’in özelliği kendisini implement eden objeyi for each döngüsünde kullanılabilir hale getirmektir. Dolayısıyla collection framework’te bulunan tüm class’ların içinde for each ile gezebileceğimiz çıkarımını yapabiliriz.

Iterable interface’inin altında karşımıza Collection interface’i çıkar. Collection, element adı verilen objelerin gruplarını temsil eder. Bazı collection’lar sıralı olur, bazıları sırasız; bazılarında tüm elementler eşsiz olur, bazılarında ise böyle bir zorunluluk yoktur. Bunları ihtiyaçlarımıza göre kullanırız.

Collection interface’inin altında ise 3 farklı interface vardır. Set, List ve Queue. Bu üç interface collection karakteristik özelliklerinin belirlendiği interface’lerdir.

1. Set

Set’in karakteristik özelliği aynı elemandan birden fazla olmasına izin vermemesi ve birden fazla null eleman kabul etmemesidir. Yani e1 ve e2 elementleri için e1.equals(e2) ise bu iki eleman aynı Set içinde barınamaz. Şimdi Set interface’inden türetilen diğer collection framework üyelerine bakalım.

HashSet

HashSet’te veriler hashleme yöntemi ile tutulur. Verilerin sırasının korunacağını garanti etmez. Yani önce e1, sonra e2 elementini kaydedip e2, e1 sırasında çekebilirsiniz. Aynı zamanda HashSet non-synchronized olduğu için birden fazla thread aynı anda bir HashSet’e erişip değiştirmeye çalışırsa problem yaşamamak için manuel bir çözüm olarak synchronized erişim sağlamalıyız.

HashSet<String> meyveler = new HashSet<String>();
	meyveler.add("Elma");
	meyveler.add("Armut");
	meyveler.add("Muz");
	meyveler.add("Çilek");

	// Aynı elementten bir tane daha eklemeye çalışıyoruz.
	meyveler.add("Armut");

	// İki tane null eklemeye çalışıyoruz.
	meyveler.add(null);
	meyveler.add(null);
	System.out.print("HashSet -> ");

	meyveler.forEach(meyve -> System.out.print(meyve + " "));

Bu kodun çıktısı bende aşağıdaki gibi oldu. Sıralama sizde daha farklı olabilir. Çünkü bildiğiniz üzere HashSet’lerde çıktı rastgele sırayla verilir.

HashSet -> null Armut Muz Çilek Elma

LinkedHashSet

HashSet’ten tek farkı, eklenen elementlerin ekleme sırasına göre tutulmasıdır. (Insertion order) Tekrarlı element eklendiğinde ilk eklenen element bundan etkilenmez.

LinkedHashSet<String> gunler = new LinkedHashSet<String>();
	gunler.add("Pazartesi");
	gunler.add("Salı");
	gunler.add("Çarşamba");
	gunler.add("Perşembe");
	gunler.add("Cuma");
	gunler.add("Cumartesi");
	gunler.add("Pazar");

	// Aynı elementten tekrar kaydediyoruz.
	// Tekrarlı element sıralamayı değiştirmeyecek.
	gunler.add("Pazartesi");

	System.out.print("LinkedHashSet -> ");
	gunler.forEach(gun -> System.out.print(gun + " "));

Bu kodun çıktısı aşağıdaki gibidir:

LinkedHashSet -> Pazartesi Salı Çarşamba Perşembe Cuma Cumartesi Pazar

TreeSet

TreeSet’lerde elementler artan sıralamayla, yani ascending order ile tutulur. null element kabul etmez. Eklenmeye çalışılırsa NullPointerException hatası verir.

TreeSet<Integer> sayilar = new TreeSet<Integer>();
	sayilar.add(4);
	sayilar.add(7);
	sayilar.add(2);
	sayilar.add(9);

	// Tekrarlı element ekliyoruz.
	// Kaydetmeyecek.
	sayilar.add(7);

	sayilar.forEach(sayi -> System.out.print(sayi + " "));

Bu kodun çıktısı aşağıdaki gibi olacaktı:

TreeSet -> 2 4 7 9

2. List

List’in karakteristik özellikleri tekrarlı elementlere izin vermesi, elementleri ekleme sırasına göre tutması ve istediğimiz index’e element eklememize izin vermesidir.

ArrayList

Collection framework’de en çok kullanılan class’tır. List özelliklerini barındırır.

ArrayList<String> sehirler = new ArrayList<String>();
	sehirler.add("Ankara");
	sehirler.add("Amasya");
	sehirler.add("Sivas");
	sehirler.add("İzmir");
	sehirler.add("Eskişehir");

	// Tekrarlı element ekliyoruz.
	sehirler.add("Amasya");

	// İstediğimiz index'e eleman ekliyoruz.
	sehirler.add(3, "Isparta");

	System.out.print("ArrayList -> ");
	sehirler.forEach(sehir -> System.out.print(sehir + " "));

Kodun çıktısı aşağıdaki gibidir:

ArrayList -> Ankara Amasya Sivas Isparta İzmir Eskişehir Amasya

LinkedList

Sonuçları bakımından ArrayList ile aynıdır. Fakat aralarında bazı farklar mevcuttur. Arama işlemlerinde LinkedList O(n) iken ArrayList’te O(1)’dir. Silme işlemlerinde ise ArrayList O(n) iken LinkedList O(1)’dir. Ekleme işlemleri de aynı sonuçları verir. Dolayısıyla eğer ekleme ve silme işlemleri sık yapılacaksa LinkedList kullanmak daha avantajlıdır. Arama işlemleri sık yapılacak ise de ArrayList daha avantajlıdır.

LinkedList<String> filmler = new LinkedList<String>();
	filmler.add("Person of Interest");
	filmler.add("Black Books");
	filmler.add("Seinfeld");
	filmler.add("Fargo");

	// İstediğimiz index'e eleman ekliyoruz.
	filmler.add(4, "Akasya Durağı");

	System.out.print("LinkedList -> ");
	filmler.forEach(film -> System.out.print(film + " "));

Kodun çıktısı aşağıdaki gibidir:

LinkedList -> Person of Interest Black Books Seinfeld Fargo Akasya Durağı

Vector

Vector, nadiren kullanılan bir classtır. Şimdiye kadar hiç kullanıldığını görmedim. Sychronized bir collection’dır ve varsayılan kapasitesi 10’dur. 11. element eklenirken kapasitesini 20 yapar. 21. elementi eklerken 40 yapar. Varsayılan kapasite ve artış değerlerini kullanıcı belirleyebilir.

3. Queue

Queue interface’i FIFO (first in first out) prensibini uygular. Yani sıraya ilk giren kişi ilk çıkar. Günlük hayattaki market sırası gibidir. Bu da çok kullanılmadığı için örnek vermiyorum.

4. Map<K,V>

Map interface’i collection sınıfına dahil değildir fakat benzer amaçlar taşıdığı aynı başlık altında öğretilir. Map’ler eşleme tablolarıdır. Bir Map’te tekrarlı key olamaz. Tüm value’lar bir key ile eşlenir ve bu key ile çağrılır.

HashMap<K, V>

HashMap’ler sıralamayı garanti etmez. null key ve null value kabul eder.

HashMap<String, String> sozluk = new HashMap<String, String>();
    sozluk.put("pencil", "kalem");
    sozluk.put("computer", "bilgisayar");
    sozluk.put("bottle", "şişe");
    sozluk.put("shoe", "ayakkabı");

    sozluk.forEach((kelimeEN, kelimeTR) -> System.out.print(kelimeEN + "-" +kelimeTR + " | "));

Bu kodun çıktısı aşağıdaki gibidir:

HashMap -> computer-bilgisayar | bottle-şişe | pencil-kalem | shoe-ayakkabı |

TreeMap<K, V>

HashMap’lerden farkı, elementleri artan sıralama (ascending) ile tutmasıdır.


TreeMap<Integer, String> alisverisListesi = new TreeMap<>();
	alisverisListesi.put(3, "Süt");
	alisverisListesi.put(4, "Yumurta");
	alisverisListesi.put(2, "Un");
	alisverisListesi.put(1, "Kakao");

	System.out.print("TreeMap -> ");
	alisverisListesi.forEach((siraNu, urun) -> System.out.print(siraNu + "." + urun + " | "));

Bu kodun çıktısı aşağıdaki gibidir:

TreeMap -> 1.Kakao | 2.Un | 3.Süt | 4.Yumurta |

HashTable<K, V>

HashMap ile benzerdir fakat aralarında bazı farklar mevcuttur. HashTable sychronized’tır, dolayısıyla performansı düşüktür. HashMap null değer alırken HashTable almaz.

Hashtable<Integer, String> menu = new Hashtable<>();
	menu.put(1, "Mercimek Çorbası");
	menu.put(2, "Alinazik");
	menu.put(3, "Pilav");
	menu.put(4, "Kola");

	System.out.print("HashTable -> ");
	menu.forEach((sira, yemek) -> System.out.print(sira + "." + yemek + " | "));

Kodun çıktısı aşağıdaki gibidir:

HashTable -> 1.Mercimek Çorbası | 2.Alinazik | 3.Pilav | 4.Kola |

Kodlara ait Github linki: https://github.com/kamer/Java-Collection-Framework