Kotlin'de Sequence — büyük veya potansiyel olarak sonsuz veri kümeleri ile etkili bir şekilde çalışmaya olanak tanıyan tembel dizilerdir. Sequence üzerindeki işlemler (örneğin, map, filter) hemen gerçekleştirilmez; bunun yerine, bir eylem zinciri oluşturulur ve hesaplama yalnızca gerekli olduğunda (terminal bir işlem, örneğin toList ile) yapılır.
Bu neden önemlidir:
Kod örneği:
val numbers = generateSequence(1) { it + 1 } .filter { it % 2 == 0 } .map { it * it } .take(5) .toList() println(numbers) // [4, 16, 36, 64, 100]
Bu örnekte, yalnızca dizinin ilk 5 elemanı gerçekten hesaplanacaktır; bu, potansiyel olarak sonsuz olduğu anlamına gelir.
Ne zaman Sequence kullanmalıyız:
Kotlin'deki
mapvefiltergibi operatörlerin normal koleksiyonlarda da tembel olabileceğini garanti edebilir miyiz? Neden?
Cevap: Hayır, Kotlin'deki standart koleksiyon işlemleri (List.map, List.filter vb.) tamamen açgözlüdür. Her işlem ara bir koleksiyon oluşturur ve tüm elemanları hemen işler. Tembellik yalnızca Sequence kullanıldığında desteklenir.
Örnek:
val data = listOf(1,2,3,4) val mapped = data.map { println("Mapping $it"); it * 2 } // Tüm değerleri hemen yazdırır
Hikaye
Büyük CSV dosyalarını (bir gigabayta kadar) işleyen bir projede, koleksiyon önce tamamen List'e yüklendi, ardından chain map/filter uygulandı. Uygulama OutOfMemory'den dolayı çöktü; sorun, büyük ara listeler oluşturmayan Sequence ile List'in değiştirilmesiyle çözüldü.
Hikaye
Birçok veritabanından raporları bir araya getiren bir backend hizmeti önce arama sonuçlarını List'te biriktiriyor ve sonra filtreliyordu: sorgular yavaşladı, GC gecikmeleri gözlemlendi. Jeneratör + Sequence'a geçiş, verileri anlık olarak birleştirmeyi sağlayarak gecikmeleri önemli ölçüde azalttı.
Hikaye
Java'dan taşınan bir proje, büyük veri akışları ile çalışırken yalnızca Kotlin'in standart genişletmelerini (map, filter) kullanarak Sequence'e geçiş yapmadan çalışıyordu; kodun Java 8 akışları gibi tembel çalıştığını varsayıyordu. Hata ciddi bellek sızıntılarına ve prod'da anlık çökmelere yol açtı.