Java ME String ve StringBuffer optimizasyonu

____________________________________________________________________

String ve StringBuffer sınıfları Java’da metinler üzerinde çalışırken en çok kullanılan sınıflardır. Dolayısıyla da cep telefonları gibi işlemci gücünün düşük olduğu aygıtlarda bu sınıflar ile ilgili işlemlerin olabildiğince hızlı olması iyidir. Bu amaçla bu sınıfları kullanırken birkaç işlem ile az da olsa optimizasyon yapabiliriz.

String nesneleri sabit bir nesnedir ve bir kez yaratıldıktan sonra değiştirilemez, StringBuffer nesneleri ise değiştirilebilirler. Bu iki sınıf kullanılırken performans açısından uygun olanını kullanmaya özen göstermeli.

String yaratma

String nesneleri aşağıdaki gibi iki farklı şekilde yaratılabilir.

  1. String string1 = “Merhaba.”;String string2 = “Merhaba.”;
  2. String string3 = new String(“Merhaba.”);String string4 = new (“Merhaba.”);

Peki cep telefonumuz için bir program yazarken bunlardan hangisini kullanmalı? İkisini de kullanabiliriz tabi ama aygıtımızın cep telefonu olduğunu düşünerek ilkini kullanmamız daha mantıklı. Çünkü string1 ve string2 aynı nesnenin referansıdır, string2 üretilirken string1’in nesnesine sadece bir referans üretilmiş olur. string3 ve string4 ise new kelimesi ile yeni nesneler üretir ki bu da daha zor ve zaman alan bir işlemdir.

String nesnelerini birleştirme

Bazen String nesnelerimizi birleştirerek farklı nesnelerdeki yazıları tek bir nesnede birleştirerek kullanmamız gerekir. Bu durumda bunu yapabileceğimiz yöntemler olarak ilk aklımıza +,  String.concat(string) ve StringBuffer.append(string) gelir. Peki bunlardan hangisi daha hızlıdır?

Genelde StringBuffer.append() yöntemi + yöntemine göre daha hızlı olarak düşünülür ama bu her zaman doğru olmayabilir. Burada önemli olan şey nesnenin değerlerinin derleme öncesinde bilinip bilinmemesidir.

Mesela birleştirilecek değerlerimiz “Merhaba,”, “ben”, “F-“, “Blog” olsun.

+ ile birleştirme kodu şöyle yazılır:
String yazi = “Merhaba,” + ” ben” + ” F-” + “Blog”;

StringBuffer için ise şöyle bir kod yazarız;
StringBuffer yazi = new StringBuffer();
yazi.append(“Merhaba,”);
yazi.append(” ben”);
yazi.append(” F-“);
yazi.append(” ME”);
En sonunda da yazi.toString() kullanarak bir işlem yapmamız gerekir.

Çalışma esnasında yukarıdaki iki yöntemin çıktısı da aynı olacaktır. İkisinin yazacağı şey de bu olacaktır; “Merhaba, ben F-Blog”.

Ancak yukarıdaki kodu derleme öncesinde yazdığımızdan bu işlemde + kullanmak StringBuffer kullanmaktan daha hızlı sonuç getirecektir! Bu nasıl olabilir diyebilirsiniz, işin sırrı ilkinde nesnelerin derleme aşamasında birleştirilmesi ve çalıştırma esnasında nesneye dokunulmaması, ikincisinde ise birleştirmenin çalıştırma esnasında yapılması. Yani derleyici ilk yöntemde derleme esnasında birleştirmeyi yapacaktır. Yani yazdığınız kodun derleme sonucu şöyle olacaktır;
String yazi = “Merhaba, ben F-Blog”;
İkinci yöntem ise derleme anında dokunulmayacak ve çalıştırma anında birleştirilecek ve bu da çalıştırma anında daha fazla zaman alacaktır.

Bunu nerede kullanabiliriz, ne işe yarar? Normalde derleyicinin derleme esnasında anlayabileceği birleştirmeleri yapmaya gerek yok gibi görünür ama bir projede çok uzun yazılar yazmanız gerekiyorsa bunları aşağıdaki şekilde yapmak kodları yazarken sizin rahatlığınıza olacaktır;

String yazi = “satır1” +
“satır2” +
“satır3”;

Bu acemi kod yazarları (ben de dahil) tarafından sık abartılan bir nokta. + işaretini kullanmaktan kaçınıyoruz ama işin içine girince zaten derleyicinin bu işlemi kendi yaptığını görüyoruz.

Eğer kod çalıştırma esnasında birleştirilecek ise StringBuffer.append() ile birleştirmek daha iyidir. Çünkü + yöntemi birleştirme esnasında hem String hem de StringBuffer nesneleri yaratır ve kullanır. Bunun sebebi + yönteminin değiştirilemez String nesnelerini değiştirmesidir, bu değiştirme için önce String nesnelerinden StringBuffer nesneleri üretir, sonra bunları append() ile birleştirir ve bunları String yapıp size geri döner. Hatta birleştirilecek nesnelerin uzunluğunu da biliyorsanız, StringBuffer nesnesini de bu uzunluğu uygun olarak oluşturursunuz ve keyfinize diyecek yoktur. Bununla ilgili de aşağıyı okuyun.

StringBuffer oluşturmada optimizasyon

StringBuffer nesneleri StringBuffer isim = new (StringBuffer) şeklinde yaratılırlar. Bu şekilde nesne StringBuffer nesneleri için standart olan 16 karakter uzunluğunda yaratılır. Bu nesneye daha sonradan nesne eklenirken bu uzunluk aşıldıkça nesnenin uzunluğu iki katının iki fazlasına çıkarılır. Yani 16 karakter uzunluğu aşılırsa 2*16+2 şeklinde bir hesapla uzunluk arttırılır ve 34 yapılır. Bu da tekrar aşılırsa 2*34+2 işlemiyle uzunluk 70 olur, tekrar arttırılırsa da 2*70+2 şeklinde bellek yettiğince işlem yapılır durur.

Bu şekilde uzunluk arttırma esnasında Java sanal makinesi belirtilen uzunlukta bir karakter dizesi yaratır, eski nesneden veriyi bu dizeye kopyalar ve yeni eklenecek karakterleri alıp buraya kopyalar ve ekleme yapılmış olur. Tabi bu da oldukça fazla işlemci zamanı kullanır.

Bu yöntemin hilesi de StringBuffer nesnesini önceden ihtiyacımız olduğu kadar uzun yaratmaktır. Bunun için de yapacağımız şey nesneyi yaratırken uzunluğunu belirtmektir;

StringBuffer yazi = new StringBuffer(int uzunluk);

Bu şekilde yeterli uzunlukta bir nesnemiz varsa bir veri eklendiğinde zaten hazır olan karakter dizesi içindeki yerine yazılır, yeni bir dize oluşturulması vs. gerekmez, bu da bize daha hızlı bir uygulama sağlar.

Bunlar oldukça basit yöntemler ama Java ME de zaten basit cihazlar için. Mümkün olsa Sun Microsystems uğraşmaz sürümünü koyardı telefona. Yani o bile bunu bilerek telefonlar için farklı bir sürüm çıkardı ise bizim de Java ME programlarımızda String ve StringBuffer kullanımına dikkat etmemiz gerekli.