Kişisel web sayfamda yazılım, teknoloji ve genel hayat hakkında paylaşımlar yapmayı hedefliyorum.

Kotlin Programlama Dersleri – Collections – 1

Merhaba, bugün diğer programlama dillerinde de bulunan Collections yapısına Kotlin tarafından bakacağız. Biraz uzun bir yazı olabilir. Şimdiden sıkı tutunun 🚀

Bir ya da daha fazla öğeyi tek bir değişkende toplamak istediğimizde Collections yapılarını kullanırız. Kotlinde Collections yapısını 3 farklı türde inceleyebiliriz:

  • List: Değişkenlerin sıralı biçimde yapılandığı, konumları belirli olan, ve tekrar edilebilen koleksiyon türleridir.
  • Set: Verilerin tekrarı olmayan, benzersiz (unique) öğelerden oluşan veri grubudur.
  • Map (Dictionary): Bir key – value yapısına sahip öğelerin toplandığı veri grubudur. Maplerde keyler benzersiz iken valueler aynı olabilir.

Collection Types

Kotlinde değişkenleri incelediğimiz yazıda mutable ve immutable kavramlarından bahsetmiştik. Aynı durum koleksiyonlarda iki farklı interface ile geçerli.

A read- only interface: Koleksiyon öğelerine erişmek için gereken işlemleri sağlar.

A mutable interface: Yukarıdaki arayüzü, yazma (ekleme, silme, güncelleme) işlemleri ile genişletir.

Bir collection mutable iken; referansını tutan değişken immutable olabilir. Collection ve referans değişkenini karıştırmamalıyız.

collections in kotlin

Collectionların üç alt türden oluştuğunu ve mutable/ immutable olmak üzere iki farklı tipi olduğundan bahsettik. Gelin bir de bunların kod karşılıklarına bakalım.

Eğer bir collection üzerinde ekleme, çıkarma gibi yazma işlemleri yapmamız gerekiyorsa collectionı mutable yani değişebilir olarak oluşturmamız gerekir. Şimdi gelin bu collection yapılarını ayrı ayrı inceleyelim.

List

List yapısı, her öğenin indexinin yani sırasının belirli olduğu ve öğelere bu indexler üzerinden eriştiğimiz yapılardır. Indexler 0’dan liste uzunluğu – 1′ e kadar gider.

Listenin elemanlarına index üzerinden ulaşabileceğimiz gibi, Kotlinin bize hazır olarak sunduğu first(), last() gibi fonksiyonları kullanarak da öğelere erişebiliriz.

Bir listenin elemanları ve sıraları başka bir liste ile aynı ise bu iki liste birbirine eşittir.

Mutable bir liste, read-only listelere ek olarak, write operation yani ekleme, silme, güncelleme gibi elemanlar üzerinde oynama kabiliyetlerine de sahiptir. Bir listeye tek tek eleman ekleyebileceğimiz gibi listeye başka bir liste de ekleyebiliriz.

Listeler, dizilere oldukça benzer fakat çok belirgin bir fark vardır. Dizilerin ilk tanımlama esnasında boyutu verilir ve değiştirilmez. Fakat listelerin boyutu write operations sonrası değişebilir.

Kotlinde mutable listelerin default implementasyonu ArrayListlerdir.

Set

Benzersiz elemanları depolamak için kullanılan collection yapısıdır. Yani aynı eleman 2 defa bulunmaz. Setler null değerleri de saklayabilir fakat bir sette her değer tek olduğu için sadece bir null değer bulunabilir. Sıralama setler için önemsizdir. Eğer iki setin boyutu ve elemanları aynı ise bu setler birbirine eşittir.

Kotlinde mutable setlerin default implementasyonu LinkedHashSettir. LinkedHashSetler, elemanların sıralarını koruyabilen bir yapıdadır. Bu nedenle first(), last() gibi fonksiyonlar kestirilebilir değerler döner.
Alternatif bir tür olan HashSetler ise, elemanların sıraları hakkında kesin bir bilgiye sahip değildir. first() gibi fonksiyonların dönüşü kestirilemez. Fakat aynı boyuttaki setlerde HashSet daha az bellek ihtiyacı duyar.

Map

Mapler Collectionlardan miras almamasına rağmen Kotlinde bir collection türü olarak kabul edilir. Mapler, verileri key – value eşlemesi ile saklar. Keyler unique yani benzersizdir fakat birden fazla key bir value işaret edebilir. Elemanlara keyler üzerinden erişilebilir.

Eğer iki map aynı değerlere sahipse, sıralarının önemi olmadan onlar eşit sayılır.
Kotlinde mutable maplerin default implementasyon türü LinkedHashMaptir ve veri ekleme, çıkarma esnasında map sırasını korur. Alternatif tür olan HashMapler ise eleman sıralaması hakkında bir bilgiye sahip değildir.

Constructing Collections

Constructing from elements

Kotlinde bir koleksiyon oluşturmanın en çok kullanılan ve pratik yolu, standard library fonksiyonlarıdır.

  • listOf<T>()
  • setOf<T>()
  • mapOf<T>()
  • mutableListOf<T>()
  • mutableSetOf<T>()
  • mutableMapOf<T>()

Bir koleksiyona vereceğimiz değerler belirli ise, bu fonksiyonları kullanabiliriz. Yukarıdaki örneklerde de olduğu gibi eğer constructorda değerleri eklersek tip belirtmemize gerek kalmaz. (Kotlin type inference)

Eğer verilerimiz belirli değilse, boş bir koleksiyon oluşturabilir daha sonrasında işlem yapabiliriz. Bu durumda ise tip belirtimi şart oluyor.

Eğer belirli bir kurala göre liste başlatmak istersek, listelerin bu iş için hazırlanmış kurulumundan faydalanabiliriz.

Copying

Mevcut bir collectiondan bir başka collection oluşturmak istersek, kotlin standard libraryde bulunan fonksiyonları kullanabiliriz.

Eğer kopyalama işlemini toList(), toMutableList() ya da toSet() fonksiyonları ile yaparsak, orjinal collectiondan anlık bir kopya alıp yeni bir collection oluştururuz. Bu yüzden yeni oluşan collection ile ile orjnalinde ekleme, güncelleme gibi işlemler sonrası benzer hareket görüntülenmez. Ama referans ile kopyalarsak, yani bir collectionı başka bir değişkene atarsak; referans paylaşımı yapmış oluruz. Yani yapılan işlemler iki collectionda da gözlenir.

Iterators

Iterators (yineleyiciler), bir koleksiyonda traverse yani gezinme işlemini gerçekleştirmek için bulunan yapıdır. Koleksiyonun üzerinde gezinen ve bize var olan değerleri verebilen bir yapıdır.

Set ve List’in yanı sıra Iteratable arayüzünü implemente eden yapılarda iterator() fonksiyonu ile elde edilir ve iterator.next() ile koleksiyonun ilk elemanını elde ederiz. Her çağrımda ise sonraki elemanı geri döner.

Mutable bir collectiondan mutable bir iterator elde edebiliriz. Iterator’a ek olarak, remove diyerek iterate eden değeri kaldırabiliriz.

Eğer listIterator kullanırsak, çift yönlü traverse imkanımız olur. hasPrevious(), hasNext() ile değerlerin varlığı kontrol edebilirken; add ve set ile listeye müdahale edebiliriz.

Sequences

Sequences, Kotlin standard library içinde bulunan bir başka yapıdır. Iterable olmasının yanı sıra birden fazla aşamalı işlemlere collectionlara göre farklı yaklaşır.

Iterable yapılarda, birden fazla aşamalı işlemlerde ( örneğin; önce filter, sonra map, sonra …) her ara işlemde bir geri dönüş gerçekleşir. Yani bir filter işlemi sonrasında verilen predictiona uygun yeni bir liste oluşturulur.

filter on Iterable
filter on Sequence

Fakat Sequencelerde, adımlar lazy gerçekleşir, sadece işlem zincirinin sonucu istendiğinde gerçekleşir.
Iterable yapılarda, bir aşama tüm elemanlar için gerçekleştirilirken; Sequencelerde aşamalar, kabul edilen elemanlar üzerinden devam eder.

Çalışma prensiplerinden dolayı aralarında ciddi performans farkı oluşan bu yapılar, her zaman kazanmaz ya da her zaman kaybetmez. Koleksiyon boyutu önemli bir kriterdir, az olduğunda iterable collectionların seçimi daha mantıklı olacaktır.

Sequenceleri birden fazla yol ile oluşturabiliriz. Ama değinmek istediğim bir nokta ise generateSequence fonksiyonu.
Bu fonksiyonumuz bizden başlangıç değeri ve bir kural fonksiyonu istiyor. Ve kural çerçevesinde bize sonsuz bir sequence hazırlıyor. Fakat Sequencelerin çalışma prensibinden dolayı biz take(n) dediğimiz noktaya kadar hazırlayıp bize sunuyor. Ya da koşul dışında null ataması yaparak sonlu bir sequence hazırlayabiliriz.

Bir başka önemli nokta ise sequence{…} ile oluşturmak. yield tek parametre alırken; yieldAll bir collection ya da sequence alabilir. Tabi yieldAll içindeki sequence sonsuz ise, o koddan aşağısı hiç çalıştırılmaz.

Sequence Operations

Sequencelerde iki farklı işlem türü vardır:

  • Stateless operations, işlemde bir duruma ihtiyaç yoktur ve tüm elemanlara bağımsız şekilde uygulanır. (map, filter gibi)
  • Stateful operations, işlem için bir state ihtiyacı vardır. Eleman sayısı ile bağlantılı işlemlerdir.

Sequence vs Iterable (Processing)

Karşılaştırmayı kotlinlang yani resmi dökümandaki örnekle açıklamaya çalışacağım. Elimizde bir kelime listesi var ve kelimeleri uzunluğu 3 den fazla olanları filtreleyip ekrana basacağız.

Önce bir liste ile deneyelim.

Baktığımız zaman filter işleminde tüm elemanlara gidiliyor ve map işleminde gereksiz elemanlar atılmış oluyor.

Şimdi sıra Sequencede…

Sequence yapısına göre, filter ve map işlemi sonuç istendiğinde çalıştırılır. Ve take ile belirtilen sayıyı elde edildiğinde durdurulur. Test kelimesinden sonra filter devam etmeden map işlemi çalıştığını görüyoruz. Bu da listelerde olduğu işlemin tüm elemanlara gezdirilmediğini gösteriyor.

Bu yazıda Kotlinde Collectionları açıklamaya çalıştım. Bir sonraki yazı bu yazının devamı niteliğinde olacak ve Collectionlarda işlemleri örneklerle açıklayacağım. Tekrar görüşmek üzere, sağlıcakla kalın 🙂

Daha fazlası için:

https://kotlinlang.org/docs/reference/collections-overview.html

https://kotlinlang.org/docs/reference/sequences.html

Share

You may also like...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir