Java 1.5 ile gelen yenilikler içerisinde bulunan Genel Tipler ile bazı kod yazma pratiklerimizi değiştirmek ve kendimizi geliştirmek zorunda kaldık. Data Access Object ve Service gibi Üst Seviye Tasarım Kalıplarında (Enterprise Design Patterns), Java Torbalarında (Collections & Map) çok sık kullanır olduk. Tasarımsal olarak getirdiği faydalar olduğu gibi kötü kullanımda da kod okunabilirliliğini azaltmaktadır. Gelin Genel Tipler'in nasıl kullanıldığını bir bakalım... Yazının diğer bölümleri : Bölüm-2
[--split--]
Nedir bu genel tipler (Generic Types)? Beynimizi çok yormaya gerek yok. Java 1.5 öncesinde bir liste oluşturduğumuzda ve bu listeden bir nesne almak istediğimizde zahmetli bir işe kalkışırdık :
1: List liste = new ArrayList();
2: liste.add(new Integer(0));
3: liste.add(new Integer(1));
4: for(int i=0; i<liste.size(); i++){
5: Integer sayi = (Integer) liste.get(i);
6: }
6. satırda olduğu gibi istediğimiz tipe dönüşüm yaparak (upcasting / downcasting) istediğimiz nesneyi kullanabilirdik.
1: List liste = new ArrayList();
2: liste.add(new Integer(0));
3: liste.add(new Integer(1));
4: liste.add(new String("test"));
5: for(int i=0; i<liste.size(); i++){
6: Integer sayi = (Integer) liste.get(i);
7: System.out.println("["+i+"] = "+ sayi);
8: }
Sonuç:
[0] = 0
[1] = 1
Exception in thread "main" java.lang.ClassCastException: java.lang.String
at com.articles.generics.objectcaching.ObjectPoolManager.main(ObjectPoolManager.java:67)
Oluşturduğumuz liste nin sadece Integer tipindeki nesneleri içereceğini düşünürken takım arkadaşımız başka bir yordam içerisinde öyle bir kod yazmışki bu liste içerisine String tipinde bir nesne atmış ( 4. satır ). Çalışma zamanında (Runtime) bu liste içerisindeki nesneleri Integer tipine dönüştürerek alırken String tipinde bir nesnenin gelmesi hata fırlamasına ve uygulamamızın durmasına neden olmaktadır.
Java 1.5 ile gelen genel tipler ( Generics ) bize tam burada yardımımıza koşmaktadır : çok sık kullandığımız Collection ve Map hiyerarşisindeki torbaların (containers) kullanımında yukarıdaki sorunların ortadan kalkması...
1: List<Integer> intList = new ArrayList<Integer>();
2: intList.add(new Integer(1));
3: intList.add(new Integer(2));
4: intList.add(new String("3"));
Satırları javac ile derlemeye çalıştığımızda :
şeklinde derleme uyarısı alırız. Çünkü 1. satırda <Integer> ifadesi (tip parametresi) ile oluşturacağımız listeye Integer tipi üzerinde işlem gerçekleştireceğimizi söyleriz. String tipinde bir nesneyi listeye koymak istediğimizde ise derleme hatası alırız. Böylece çalışma zamanında (Runtime) beklenmedik tip dönüşümlerinden meydana gelen hatalardan kurtulmuş oluruz.
Nesne Havuzu ( Object Pool )
Jenerik yapıları anlamak için gelin bir uygulama geliştirelim. Bu uygulama veritabanı bağlantı havuzu (DB Connection Pool) yada iş parçacıkları havuzu (Thread Pooling) gibi asıl amacı sürekli tekrarlayan işlemlerde belli bir tipteki nesnelerin her seferde oluşturulması ve silinmesini engellemektir. Böylece uygulamada gereksiz yavaşlamaları engelleyebilir ve nesne takibini iyileştirebiliriz.
Gelin öncelikle uygulamamızı süper yapıları tanımlayarak başlayalım. Bu süper yapılar : arayüzler (interface), süper sınıflar (super class) ve soyut sınıflar (abstract class) olabilir.
Süper yapılara üzerinden uygulamamızı geliştirdiğimiz zaman ileriye yönelik geliştirme ve sistemler arası iletişim daha kolay yapılmış olacaktır.
Oluşturacağımız süper yapılar:
1. Yedeklenebilir Arayüzü (Interface) : Sistem tarafından havuzda tutalacak olan nesnelerin sınıf tanımlamaları bu arayüzü gerçekleştirmelidir.
2. Havuz Arayüzü (Interface) : doldur(), cek()/koy(), bos() soyut yordamlarını içeren arayüzdür. Bu arayüzü gerçekleştiren sınıflar <<Yedeklenebilir>> arayüzünü gerçekleştirmiş yapılar için sınırlandırılmalıdır.
3. HavuzYöneticisi Arayüzü (Interface) : nesneCek(), nesneKoy() ve havuzuKontrolEt() yordamlarını içermektedir.
a. nesneCek() yordamı istenen nesnenin tipine göre ilgili havuzdan nesne çekecek
b. nesneKoy() yordami gönderilen nesneyi, nesnenin tipine göre ilgili havuza geri koyar.
c. havuzuKontrolEt() yordami nesneCek() yordami çağrıldığında ilgili nesne için havuz nesnesinin yaratılıp içerisinin doldurulmasını kontrol eder.

Havuz Arayüzü
/**
*{@link Yedeklenebilir}arayüzünügerçekleştirmiş
*nesneleriçinhavuzgörevinigörür.
*
*@param<T extends YedeklenebilirNesne>
*/
public interface Havuz <T extends Yedeklenebilir> {
/**
*Havuzdannesneçeker.
*@returnT
*/
T cek();
/**
*Nesneyigerikoyar.
*@paramobject
*/
void koy(T nesne);
/**
*clazztipindenesneleriyaratipkendisinidoldurur.
*@paramclazz
*@throwsNesneYaratmaHatasi
*/
void doldur(Class<T> clazz) throws NesneYaratmaHatasi;
/**
*clazztipindenesnelerdenbelirtilenadetkadar
* yaratipkendisinidoldurur.
*@paramclazz
*@paramadet
*@throwsNesneYaratmaHatasi
*/
void doldur(Class<T> clazz, int adet) throws NesneYaratmaHatasi;
/**
*Havuzunbosolupolmadigikontroledilir
*@returnboolean
*/
boolean bos();
}
Havuz arayüzüne ait yukarıdaki tanımlamada dikkatimizi <T extends Yedeklenebilir> tip parametresi çekmektedir. Böylece Havuz arayüzünü sadece Yedeklenebilir arayüzüne erişmiş yapılar için genelleştirmiş / sınırlandırmış (bounding) olduk.
[--split--]
Nedir bu genel tipler (Generic Types)? Beynimizi çok yormaya gerek yok. Java 1.5 öncesinde bir liste oluşturduğumuzda ve bu listeden bir nesne almak istediğimizde zahmetli bir işe kalkışırdık :
1: List liste = new ArrayList();
2: liste.add(new Integer(0));
3: liste.add(new Integer(1));
4: for(int i=0; i<liste.size(); i++){
5: Integer sayi = (Integer) liste.get(i);
6: }
6. satırda olduğu gibi istediğimiz tipe dönüşüm yaparak (upcasting / downcasting) istediğimiz nesneyi kullanabilirdik.
1: List liste = new ArrayList();
2: liste.add(new Integer(0));
3: liste.add(new Integer(1));
4: liste.add(new String("test"));
5: for(int i=0; i<liste.size(); i++){
6: Integer sayi = (Integer) liste.get(i);
7: System.out.println("["+i+"] = "+ sayi);
8: }
Sonuç:
[0] = 0
[1] = 1
Exception in thread "main" java.lang.ClassCastException: java.lang.String
at com.articles.generics.objectcaching.ObjectPoolManager.main(ObjectPoolManager.java:67)
Oluşturduğumuz liste nin sadece Integer tipindeki nesneleri içereceğini düşünürken takım arkadaşımız başka bir yordam içerisinde öyle bir kod yazmışki bu liste içerisine String tipinde bir nesne atmış ( 4. satır ). Çalışma zamanında (Runtime) bu liste içerisindeki nesneleri Integer tipine dönüştürerek alırken String tipinde bir nesnenin gelmesi hata fırlamasına ve uygulamamızın durmasına neden olmaktadır.
Java 1.5 ile gelen genel tipler ( Generics ) bize tam burada yardımımıza koşmaktadır : çok sık kullandığımız Collection ve Map hiyerarşisindeki torbaların (containers) kullanımında yukarıdaki sorunların ortadan kalkması...
1: List<Integer> intList = new ArrayList<Integer>();
2: intList.add(new Integer(1));
3: intList.add(new Integer(2));
4: intList.add(new String("3"));
Satırları javac ile derlemeye çalıştığımızda :
şeklinde derleme uyarısı alırız. Çünkü 1. satırda <Integer> ifadesi (tip parametresi) ile oluşturacağımız listeye Integer tipi üzerinde işlem gerçekleştireceğimizi söyleriz. String tipinde bir nesneyi listeye koymak istediğimizde ise derleme hatası alırız. Böylece çalışma zamanında (Runtime) beklenmedik tip dönüşümlerinden meydana gelen hatalardan kurtulmuş oluruz.
Nesne Havuzu ( Object Pool )
Jenerik yapıları anlamak için gelin bir uygulama geliştirelim. Bu uygulama veritabanı bağlantı havuzu (DB Connection Pool) yada iş parçacıkları havuzu (Thread Pooling) gibi asıl amacı sürekli tekrarlayan işlemlerde belli bir tipteki nesnelerin her seferde oluşturulması ve silinmesini engellemektir. Böylece uygulamada gereksiz yavaşlamaları engelleyebilir ve nesne takibini iyileştirebiliriz.
Gelin öncelikle uygulamamızı süper yapıları tanımlayarak başlayalım. Bu süper yapılar : arayüzler (interface), süper sınıflar (super class) ve soyut sınıflar (abstract class) olabilir.
Süper yapılara üzerinden uygulamamızı geliştirdiğimiz zaman ileriye yönelik geliştirme ve sistemler arası iletişim daha kolay yapılmış olacaktır.
Oluşturacağımız süper yapılar:
1. Yedeklenebilir Arayüzü (Interface) : Sistem tarafından havuzda tutalacak olan nesnelerin sınıf tanımlamaları bu arayüzü gerçekleştirmelidir.
2. Havuz Arayüzü (Interface) : doldur(), cek()/koy(), bos() soyut yordamlarını içeren arayüzdür. Bu arayüzü gerçekleştiren sınıflar <<Yedeklenebilir>> arayüzünü gerçekleştirmiş yapılar için sınırlandırılmalıdır.
3. HavuzYöneticisi Arayüzü (Interface) : nesneCek(), nesneKoy() ve havuzuKontrolEt() yordamlarını içermektedir.
a. nesneCek() yordamı istenen nesnenin tipine göre ilgili havuzdan nesne çekecek
b. nesneKoy() yordami gönderilen nesneyi, nesnenin tipine göre ilgili havuza geri koyar.
c. havuzuKontrolEt() yordami nesneCek() yordami çağrıldığında ilgili nesne için havuz nesnesinin yaratılıp içerisinin doldurulmasını kontrol eder.
Havuz Arayüzü
/**
*{@link Yedeklenebilir}arayüzünügerçekleştirmiş
*nesneleriçinhavuzgörevinigörür.
*
*@param<T extends YedeklenebilirNesne>
*/
public interface Havuz <T extends Yedeklenebilir> {
/**
*Havuzdannesneçeker.
*@returnT
*/
T cek();
/**
*Nesneyigerikoyar.
*@paramobject
*/
void koy(T nesne);
/**
*clazztipindenesneleriyaratipkendisinidoldurur.
*@paramclazz
*@throwsNesneYaratmaHatasi
*/
void doldur(Class<T> clazz) throws NesneYaratmaHatasi;
/**
*clazztipindenesnelerdenbelirtilenadetkadar
* yaratipkendisinidoldurur.
*@paramclazz
*@paramadet
*@throwsNesneYaratmaHatasi
*/
void doldur(Class<T> clazz, int adet) throws NesneYaratmaHatasi;
/**
*Havuzunbosolupolmadigikontroledilir
*@returnboolean
*/
boolean bos();
}
Havuz arayüzüne ait yukarıdaki tanımlamada dikkatimizi <T extends Yedeklenebilir> tip parametresi çekmektedir. Böylece Havuz arayüzünü sadece Yedeklenebilir arayüzüne erişmiş yapılar için genelleştirmiş / sınırlandırmış (bounding) olduk.