Şuanda sabahın saat 3 buçuğu. Yeni hazırladığım
sıcak kahvemi yudumlarken, Java ile ilgilenmekten saatın ne kadar geç olduğunun
farkına bile varamadım. Geçen hafta boyunca, Java programlama dilinin
temellerini incelemeye devam ettim. Doğruyu söylemek gerekirse, sıkıcı olan bir
kaç konu inceledim. Bunlardan birisi dizilerdi.
Hemen her programlama dilinde olduğu gibi
dizilerinde java'da sıkıcı bir yeri var. Sıkıcı olmasını nedeni belkide, veri
saklama ile ilgili olarak günümüz teknolojilerinin getirdiği veritabanı, xml,
gelişmiş koleksiyonlar gibi kavramların çok daha fazla tercih ediliyor olması.
Ancak ne olursa olsun, hangi programlama dili olursa olsun ve kavramları ne
kadar sıkıcı olursa olsun, bunları bilmekte, incelemekte fayda var.Bu sabah
saatlerindeki kahve molamda, dizilerin Java programlama dili içindeki yerini
incelemeye çalışacağım. Bir diziyi belkide en güzel şu şekilde tanımlayabiliriz.
|
Dizi, belli bir sayıda ve aynı veri türünden
değişkenlere, aynı isim altında erişilmesini sağlayan bir referanstır. |
Aslında bu tanım içerisinde çok geniş kavramlar
var ve açıklanması gerekli. Herşeyden önce, dizilerin referans olduklarını
söylüyor. Java dilindede, C#'ta olduğu gibi diziler referans tipli verilerdir.
Dolayısıyla bir dizi, belleğin yığın (stack) kısmında tutulurken, dizi
elemanlarının tamamı, öbek (heap)'te yer alır. Yani dizinin adı, öbekteki
elemanların başlangıç adresine işaret eder. Bu dizilerin en önemli unsurlarından
birisidir. Diğer yandan, diziler aynı veri türünden elemanlara sahip olmalıdır.
Bununla birlikte dizilerin eleman sayısıda oluşturulurken belirlenir.
Dolayısıyla, bir diziyi en baştan boyutlandırdığımızda, beliltilen sayıda
elemanı aktarabiliriz ve buda dizinin boyutu ile dinamik olarak oynamamızı
engeller. Doğruyu söylemek gerekirse bu kısıtlamalar belkide C# dilinde
koleksiyonları geliştirilmesine ve daha çok önem kazanmasına neden olmuştur.
Kimbili belki Java dilinde'de koleksiyonlar var. Şimdilik karşıma çıkmadılar.
O halde işe referans veri tipi olan dizilerin
nasıl tanımlanacağından başlamak gerekiyor. Referans tipli olması, dizilerin
oluşturulurken new yapılandırıcı kullanılarak oluşturulması gerektiği sonucunu
ortaya çıkartıyor. Nitekim, diziler referans tipli nesnelerdir. Dolayısıyla bir
sınıf örneği olmak zorundalar. Ancak diğer yandan, bir diziyi oluştururken new
yapılandırıcısını kullanmak zorunda değiliz. Dizi elemanlarına, 0 tabanalı bir
indis sistemi ile erişebilmekteyiz. Bu anlamda dizilerin, döngüler ile kardeş
olmalarını gayet iyi anlayabiliyorum. Şimdi dizi kavramını incelemek için basit
ama hızlı bir örnek geliştirmek düşüncesindeyim. Kahvemden bir yudum alıyorum ve
aşağıdaki örneği yazıyorum.
|
public class Dizi
{
public static void main(String[] args)
{
int dizi1[]=new int[10];
for(int i=0;i<dizi1.length;++i)
{
dizi1[i]=i*2;
System.out.println((i+1)+". eleman="+dizi1[i]);
}
}
} |
Uygulamayı başarı ile derledikten sonra
çalıştırdığımda aşağıdaki sonucu aldım.

Kodların çalışma sistematiği oldukça basit. Diziyi tanımlaka için
new yapılandırıcısını kullandık ve dizinin integer veri tipinden 10 elemanlı
olmasını sağladık. Bu noktadan sonra dizimize elemanlar atamak için bir döngü
kullandık. Bu döngü dizimizin boyutuna kadar hareket eden ve her bir elemana
indis değerinin iki katını aktaran bir yapıda. Kullandığımız length özelliği,
dizilerin boyutunu elde etmekte kullanılmakta. Buradanda zaten, dizilerin bir
Java sınıfına ait olduğu sonucuna varabiliriz. Kodumuzda, dizi elemanlarını
okumak içinde aynı döngü içindeki dizi1[i] şeklindeki yazımı kullandık. Dizileri
yukarıdaki örnekte olduğu gibi new yapılandırıcısı ile tanımlayabileceğimiz
gibi, başka alternatif bir yoluda kullanabiliriz. Benzer bir örnek uygulam
aşağıda yer alıyor.
|
public class Dizi2
{
public static void main(String[] args)
{
int[] dizi={1,3,5,7,9,11,13,15};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
}
} |

Burada diziyi tanımlarken elemanlarınıda baştan atamış olduk. Bu
aynı zamanda verdiğimiz eleman sayısına göre dizinin otomatik olarak
boyutlandırıldığınıda göstermektedir. Son örneğimizin bellekteki yerleşim
planına göz atarsak aşadıdaki tasvire benzer bir yapının oluştuğunu görürüz.

Peki ya bir diziye taımlandığı veri tipinden başka bir tipte
eleman eklemeye kalkarsak ne gibi sonuçlarla karşılaşabiliriz. Doğrusu bunu
merak ediyorum. Bu nedenle yukarıdaki örnekte, integer tipteki dizimize, başka
bir veri tipinden eleman eklemeye karar verdim. Bu amaçla, 'a' karakterini
sincizce dizi elemanları arasına yerleştirdim.
|
public class Dizi2
{
public static void main(String[] args)
{
int[] dizi={1,3,5,7,9,11,'a',15};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
}
} |
Uygulamayı derlediğimde her hangibi hata mesajı
ile karşılaşmadım. Diğer yandan uygulamayı çalıştırdığımda aşağıdaki hata mesajı
beni bekliyordu.

Vouv! Hiç beklemediğim bir durum. 7nci eleman yani 'a' değerinin
karakter karşılığı oluvermişti bir anda. Hımm. Aslında bu istemediğim bir sonuç.
Ben daha çok bir hata mesajı bekliyordum. Yoksa dizi tanımında bir tanımlama
hatasımı yaptım? Denemeye devam etmeye karar verdim. Sabahın kaçı olursa olsun
ben bu hata mesajını bulacaktım. Kodları aşağıdaki şekilde değiştirdim. Aklıma
ilk gelen integer değilse bir double değeri buraya koymak oldu. Hatta bir tane
değil bir kaç farklı veri tipinden değerler koymak.
|
public class Dizi2
{
public static void main(String[] args)
{
int[] dizi={1,"Selam
naber",5,true,9,11,15.154654,15};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
}
} |
Sonunda başardım. İstediğim hata mesajlarını aldım ve dizi
tanımına sadık kaldım.

Ancak dizileri kullanırken başıma gelebilecek diğer hatalarıda
incelemek istiyorum. Öncelikle dizide olmayan bir indis elemanı oluşturmak
istersem veya ona ulaşmak istersem ne olur? Fazla söze gerek yok hemen kodları
yazmak lazım. Bu kez 5 elemanlı bir diziye 6ncı elemanı eklemeye çalışacağım.
|
public class Dizi2
{
public static void main(String[] args)
{
int[] dizi={1,2,3,4,5};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
dizi[6]=7;
}
} |
Uygulama yine hatası olarak derlendi. Umarım bu
sefer çalıştırdığımda istediğim hatayı alabilirim. Evet. Mükemmel. Hatayı elde
etmeyi başardım.

Dizileri tanımlarken, aynı veri türünden
elemanları grupladığımızdan bahsetmiştik. Farklı bir durum daha vardır. Bu da
bir diziyi Java dilinin en üst sınıf olan (C# taki gibi) Object türünden
tanımlamak ve elemanları birer nesne olarak belirlemektir. Bu teknikte, dizinin
tüm elemanları birer nesnedir. Bu anlamda bellekteki dizilişte farklı
olmaktadır. Öyleki, Object türünden bir dizi tanıladığımızda, dizinin elemanları
öbekte tutulurken her bir eleman nesne olduğu için, yine öbekteki asıl
alanlarına referans eden değerleri taşırlar. Ancak dizi elemanlarına
eriştiğimizde, bu nesnelerin referans ettikleri öbek alanlarındaki verilere
ulaşılır. Hemen bununla ilgili bir örnek yapmakta fayda var.
|
public class DiziObject
{
public static void main(String[] args)
{
Integer eleman1=new Integer(456);
String eleman2=new String("Ben bir
stringim...");
Double eleman3=new Double(45.45687);
Boolean eleman4=new Boolean(true);
Object[]
dizi={eleman1,eleman2,eleman3,eleman4};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
}
} |
Burada yaptığım Object türünden dizim için, new
yapılandırıcılarını kullanarak sırasıyla integer, string, double ve boolean veri
türlerinden birer nesne yaratmak ve daha sonra bu nesneleri Object türünden
diziye aktarmak. Uygulama başarılı bir şekilde derlenicektir ve çalışacaktır.

Bu tekniğin bellekteki görünümü ise aşağıdaki
tasvire benzer şekilde olucaktır.

Tabi burada aynı örneği aşağıdaki şekide
geliştirmeyide düşündüm ama bu durumda hata mesajları ile karşılaştım. Çünkü
aşağıdaki tekniği uygulayarak bir Object dizisi oluşturmaya çalıştığımda,
elemanların her biri birer değişken olarak algılandı ve Object dizisine
eklenmeye çalışılmak istendi. Ancak Object türünden bir dizi, kendisi gibi nesne
elemanlarını kabul edeceğinden temel veri türlerinden tanımlanmış değişlenleri
kabul etmedi ve derleyici bir sürü hata mesajı verdi.
|
public class DiziObject
{
public static void main(String[] args)
{
Object[] dizi={456,"Ben bir
stringim",45.45687,true};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
}
} |

Ancak burada dikkat etmemiz gereken bir nokta var.
O da, String tipteki "Ben bir stringim" için bir hata mesajı almamış olmamız.
Bunun nedeni aslında çok açık. Nitekim String veri türü, bir referans türüdür.
Dolayısıyla new yapılandırıcısı ile bir String nesnesi yaratabiliriz. Bununla
birlikte new yapılandırıcısın kullanmadan yukarıdaki gibi bir string
tanımlamakta yine aynı işlevi gerçekleştirecektir. Sanırım burada bir dip not
olarak şu iki ifadeninde eşit olduklarını söyliyebiliriz.
|
String s=new String("Merhabar"); |
String s="Merhaba"; |
Gelelim diziler ile ilgili ne tür işlevleri
gerçekleştirebileceğimize. Dizilerin Java'nın bir sınıfı olduğu söylemiştik.
Evet, diziler aslında, java.util.Arrays sınıfının örneklenmiş nesneleridir.
Geçen kahve molamdada internetten indirdiğim jsdk dökümanları içinde bu sınıfı
aradım ve sayısız pek çok metodunun olduğunu gördüm. Bunların hepsini incelemek
için sanıyorumki bir kaç hektar kahve tarlamın olması, bunları öğütücek ve
işlemden geçirerek sütlüsünü, 5 şekerlisini çıkartıp bana sunacak bir fabrikam
olması gerekiyor. Ama sanıyorumki bu kahve molasında en çok işime yarayacakları
incelesem iyi olur. İlk gözüme çarpan aynı isimli metodlardan hemen her veri
türü için aşırı yüklenmiş varyasyonların oluşuydu. Örneğin sort metodunu ele
alalım. Adındanda anlaşılacağı üzere bu metod dizi elemanlarını sıralıyor.
Elbette dizinin tipine bağlı olarak gerçekleştirilen bir sıralama bu. Aşağıdaki
örnekte, integer değerlerden oluşan bir diziyi şu metod prototipini kullanarak
sıralattım.
|
public static void sort(int[] a) |
Şimdide kodlarımızı yazalım.
|
import java.util.*;
public class DiziSirala
{
public static void main(String[] args)
{
int[]
dizi={8,6,3,56,12,3,1,0,23,-1,-5};
System.out.println("Siralanmamis
Hali");
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
System.out.println("");
System.out.println("Siralanmis
Hali");
Arrays.sort(dizi);
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
}
} |

Burada öncelikle Arrays.sort metodunu kullanarak
sıralam işlemini yapmak için, java.util paketini import anahtar kelimesi ile
uygulamamıza ekledik. Bu C# taki namespace'lerin using ifadesi ile eklenmesi ile
aynı şey. Integer veri türleri için tasarlanmış bu metodun diğer veri türleri
için aşırı yüklenmiş versiyonlarıda mevcut. Burada metodumuz parametre olarak
dizinin adını alıyor ve dizinin tipine bakarak uygun olan sort metodunu
çalıştırıyor. Sort metodunun bir diğer versiyonuda aşağıda prototipi verilen
versiyondur.
|
public static void sort(int[] a,int fromIndex,int toIndex) |
Bu aşırı yüklenmiş versiyona göre, dizinin sadece
belirli indisler arasındaki elemanlarının sıralanmasını sağlamış oluyoruz.Bunu
yukarıdaki örneğimize uygularsak;
|
import java.util.*;
public class DiziSirala
{
public static void main(String[] args)
{
int[]
dizi={8,6,3,56,12,3,1,0,23,-1,-5};
System.out.println("Siralanmamis
Hali");
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
System.out.println("");
System.out.println("Siralanmis
Hali");
Arrays.sort(dizi,5,10);
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
}
} |

Bir diğer ilginç metod ise BinarySearch metodu.
Sort metodunda olduğu gibi bu metodda diğer tüm veri türleri için aşırı
yüklemiş. Prototipi aşağıdaki gibi olan bu metod, dizi içindeki bir elemanın var
olup olmadığına bakıyor ve buna göre bir sonuç döndürüyor.
|
public static int binarySearch(int[] a,int key) |
Şimdi bu metod ile ilgili bir deneme yapmanın tam sırası.
|
import java.util.*;
public class DiziBul
{
public static void main(String[] args)
{
int[]
dizi={8,6,3,56,12,3,1,0,23,-1,-5};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
System.out.println("");
int
sonuc=Arrays.binarySearch(dizi,56);
System.out.println("Arama sonucu
"+sonuc);
}
} |
İlk sonuçlar hiçte iç açıcı olmadı benim için.
Herşeyden önce aşağıdaki gibi anlamsız bir sonuç elde ettim.

Dökümantasyonu yeniden incelediğimde herşeyin
sebebi anlaşılıyordu. BinarySearch metodunu kullanabilmem için, dizinin mutlaka
sıralanmış olması gerekiyor. Bu nedenle koda, sort metodunuda ekledim. Bu
durumda, dizimizin sıralanmış hali üzerinden arama işlemi başarılı bir şekilde
gerçekleştirilmiş oldu. BinarySearch metodunun çalıştırılıması sonucu dönen
değer, aradığımız elemanın dizi içindeki indis numarasıdır.
|
import java.util.*;
public class DiziBul
{
public static void main(String[] args)
{
int[]
dizi={8,6,3,56,12,3,1,0,23,-1,-5};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
System.out.println("");
Arrays.sort(dizi);
int
sonuc=Arrays.binarySearch(dizi,56);
System.out.println("Arama sonucu
"+sonuc+".eleman"+dizi[sonuc]);
}
} |

Şimdi daha değişik bir durumu inceleyelim. Eğer
dizi içinde olmayan bir eleman ararsak binarySearch metodu nasıl bir sonuç
döndürecektir. Bu amaçla aşağıdaki kodu hazırladım. Örnek içinde, iki adet
negatif ve iki adet pozitif tamsayıyı dizi içerisinde arattım. Bu elemanların
hiçbirisin dizinin bir elemanı değil. Sonuçlara baktığımda dizide olmayan
pozifit elemanlar için -12 değerini, dizide olmayan negatif elemanlar için ise
-1 değerini elde ettim. Pozifit ve negatif elemanlar için binarySerach metodunun
döndürdüğü değerler farklı olmasına rağmen ikise negatiftir. Dolayısıyla negait
olmaları dizinin elemanı olmadıklarını göstermektedir.
|
import java.util.*;
public class DiziBul
{
public static void main(String[] args)
{
int[]
dizi={8,6,3,56,12,3,1,0,23,-1,-5};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
System.out.println("");
Arrays.sort(dizi);
int
sonuc1=Arrays.binarySearch(dizi,156);
System.out.println("Arama sonucu
"+sonuc1);
int
sonuc2=Arrays.binarySearch(dizi,-8);
System.out.println("Arama sonucu
"+sonuc2);
int
sonuc3=Arrays.binarySearch(dizi,1000);
System.out.println("Arama sonucu
"+sonuc3);
int
sonuc4=Arrays.binarySearch(dizi,-4568);
System.out.println("Arama sonucu
"+sonuc4);
}
} |

Demekki binarySearch metodunu bir if koşulu ile
kullanarak aranan elemanın dizi içerisinde olup olmadığını belirleyebiliriz.
|
import java.util.*;
public class DiziBul
{
public static void main(String[] args)
{
int[]
dizi={8,6,3,56,12,3,1,0,23,-1,-5};
for(int i=0;i<dizi.length;++i)
{
System.out.println((i+1)+". eleman="+dizi[i]);
}
System.out.println("");
Arrays.sort(dizi);
int
sonuc1=Arrays.binarySearch(dizi,156);
if(sonuc1<0)
{
System.out.println("BULUNAMADI");
}
else
{
System.out.println("BULUNDU");
}
}
} |

Arrays sınıfı ile ilgili daha pek çok metod vardı
ve bunlarıda incelemek istiyordum. Ama hava aydınlanmaya ve içmeyi unuttuğum
kahvemde ice-cafe olmaya başlamıştı. Sanırım ara vermek için en uygun zaman.
Biraz dinlenmeyi hakkettik. İlerleyen kahve molalarında kahvemi içmeyi
unutmayacağım.
Burak Selim ŞENYURT
selim@bsenyurt.com