My Profile Photo

Mehmet Cem Yücel


En yalın haliyle paylaşım platformu
Java Cloud Mikroservis Spring Boot NoSQL Kafka Dağıtık Sistemler Big Data ve Blockchain hakkında karalamalarım


Mutable - Immutable Types

Bugün bir çoğumuzun bildiği ama çoğu zaman dikkat etmediğimiz bir konuya dikkat çekmek istiyorum. Mutable(değişebilir) ve immutable(değişemez) tipler. Hangi veri tiplerimiz niçin bu özellikte, performansa etkileri ne şekilde bunlar üzerinde yorumlar yapacağız.

Örneklerim java üzerinden olacak. Ufak bir örnekle başlamadan önce String tipinin aslında bir karakterler dizisi olduğunu, bu veri tipinin primitive(ilkel) bir tipi olmadığını hatırlatma gereksinimi duyuyorum.

Bu örneğimizde string bir değişkenimize defalarca concatenating(bağlama) işlemi yapacağız. Iterasyon(tekrarlama) sayısını yüksek tuttum ki fark daha net anlaşılsın. Örnekte 100.000 kez, varolan bir stringin sonuna bir değer ekleme işlemi yapıyoruz. Bu işlem arasında geçen süreyi hesaplıyoruz.

public class Test {

public static void main(String[] args) {

String deneme=null;

long time=System.currentTimeMillis();

for (int i = 0; i < 100000; i++) {

deneme +=i;

}

System.out.println(System.currentTimeMillis() - time); // 52860ms

}

}

Bu iterasyon için geçen süre yaklaşık 52.000ms. Bu işleme A işlemi ismini verelim.

Aynı işlemi bir de StringBuffer sınıfını kullanarak yapalım ve süreyi ölçelim.(İsmi B işlemi olsun)

public class Test {

public static void main(String[] args) {

StringBuffer sb = new StringBuffer();

long time=System.currentTimeMillis();

for (int i = 0; i < 100000; i++) {

sb.append(i);

}

System.out.println(System.currentTimeMillis() - time); // 7ms

}

}

Arada nasıl oluyor da bu kadar büyük bir süre farkı oluyor? Birçoğunuzun String’in immutable bir tip olduğunu söylediğinizi duyar gibiyim. Peki nedir bu kavram, nasıl oluyor da StringBuffer çok daha hızlı bir şekilde bu işi gerçekleştiriyor?

Durumun aslını özetlemek gerekirse, concatenating(A) işleminde değişkenimiz üzerinde yapılan her işlem aslında yeni bir String değişken instance(örneği) almak anlamına geliyor. Yani klasik örnekle göstermek gerekirse

deneme +=”cem”;
new String(deneme+”cem”);

işlemleri birebir aynı işlemler. Ben 100.000 kez bu işlemi tekrarladığımda her defasında büyüyen karakter dizim için dizinin sığabileceği boyutta bellekte alan aramaya çalışıyorum. Aynı zamanda tek kullanım yaratılıp sonrasında işi biten nesneyi de garbage collector‘ın temizlemesine bırakıyorum. Yani ekstra iş yükü ekstra iş yükü. 100.000 kere yeni string yaratıp sonunda 1 tane string kazanıyorum.

Peki B işleminde ne yapıyoruz? StringBuffer sınıfı JDK1.0 ile gelen bir sınıf. Her append işleminde

sb.insert(sb.length(), [eklenecek string]) şeklinde işlem gerçekleştirilir. Özetle burada yapılan yeni bir string alıp değerleri orada tutmak değil, varolan stringin kapasitesi artırılıp sonuna insert edilmesidir. Kapasitenin artırılması JVM tarafından otomatik olarak gerçekleştirilmektedir. Bu işlem asenkron olarak işlemektedir. Aynı işlemi thread safe olmayarak gerçekleştiren bir sınıf JDK 1.5 ile gelmiştir. Adı StringBuilder‘dır. Kısacası StringBuilder sınıfı StringBufferdan çok ufak bir miktar daha hızlıdır, aradaki hız farkı senkronizasyon için harcanan vakittir. Concatenation’dan çok çok daha hızlı olduğunu yine hatırlatmakta fayda var.`
Bir sonraki yazıda Java’da immutable-mutable olması açısından primitive veri tipleri, Object’ler ve referans yapıları hakkında bahsedeceğim. Herkese bol kodlu günler.

comments powered by Disqus