İçindekilerGirişİndex
YukarıİlkÖncekiSonrakiSon
Geriİleri
Yazdır
Ahmet A Akın
ahmetafsinakin@yahoo.com

J2SE 1.5 Tiger - Yeni Dil Ozellikleri

Giris

Bugunlerde ilk alfa surumu cikan kod adi "Tiger" (kaplan) olan J2SE 1.5 (Java 2 Platform Standard Edition Release1.5) pek cok yeniligi de beraberinde getiriyor. J2SE, bilindigi uzere java'nin ozellikle masaustu ve istemci (client) uygulamalari gelistirmek icin gerekli yazilima, J2RE ise java uygulamalarinin calismasi icin gerekli java sanal makineye (virtual machine) verilen isim. Tiger ile java platformuna pek cok eklenti yapilmis olsa da bu yazida sadece kodlama kurallarina iliskin yeni dil ozelliklerinden bahsedilecektir.

Oncelikle sunu belirtmek gerekiyor ki, dil eklentileri java'ya islevsel yenilikler getirmiyor (bu yenilikler kutuphaneler ve siniflar ile geliyor ve icerigi buraya sigmayacak kadar fazla olurdu. Bu yazida bunlardan bahsedilmeyecek) sadece yazilim gelistirme konusunda yazilimcilarin karsilastigi bazi zorluklari giderip hata yapma ihtimalini azaltiyor, daha guvenli kodlama ve gereksiz yere uzun zaman alan bazi rutin islemleri derleyicinin devralmasini sagliyor. Bu eklentiler yapilirken en az sayida yeni kod kelimesi eklenmesi temel alinmis. Bu ozellikler sayesinde java'nin C#'a karsi olan bazi dil zaaflari da ortadan kalkmis oluyor. J2SE 1.5 ile onceki java surumleri ile yazilmis tum yazilimlarin desigmeden calismasi garanti ediliyor.

Bu yazi ile java konusunda en azindan temel egitim almis okuyuculari hedef almaktadir. Yazi icin editor olarak Mozilla Composer, kodlarin HTML'ye donusturulmesi icin Java2Html urununden yararlanilmistir. Yazidaki bilgilerin bir kismi ve ornekler cesitli makale ve sunumlardan derlenmistir. Kodlarda turkcelestirme ve icerisiginde kucuk oynamalar gerceklestirildi, bu sirada meydana gelen hatalardan dolayi kodlar calismayabilir. Yazi ile ilgili elestiri ve duzeltmeleri altta yer alan e-posta ya da web adresi araciligi ile gonderebilirsiniz.

Java 1.5'in alfa surumunu indirmek ve kurulum ile ilgili bilgi icin IBM'in yayinladigi su makaleden yararlanabilirsiniz. Ancak dikkatli olun, cunku su andaki java yazilim gelistirme araclari henuz Tiger'i desteklemiyor ,ortada JavaDoc bile yok ve kurulum kucuk bir ihtimalle varolan java yazilimlarini etkileyebilir. Ayrica sadece komut satirindan yazilimlari calistirabilirsiniz. Gelelim asil konuya, yeni dil ozellikleri su sekilde:

1- Generics

Javada nesne gruplarinin tasindigi Koleksiyon (Turkce tam olarak ne isim veriliyor bilemiyorum, java'daki adi Collection) yapisindaki elemanlara erisim siklikla gerceklesitirilen bir islemdir. Collection iclerinde sadece "Object" sinifindan tureyen nesneleri tutar. Java'daki tum siniflar (ilkel yapilar int, float vs haric) Object sinifindan turediginden tum siniflar Koleksiyon yapisina eklenebilir. Ancak, bir Koleksiyon 'dan nesnenin geri cekilmesi genellikle tatsiz ve zaman alici bir islemdir. Bir nesneyi Koleksiyon'dan cekmek icin atama (casting) islemi gerceklestirmeniz gerekir ve bu istenmeyen "calisma ani" hatalarina yol acabilir (runtime error) Ornegin String'lerin yer aldigi bir Koleksiyon'dan 4 harf uzunluklu olan stringleri silen bir metodu dusunelim, J2SE 1.5'ten once:

// Dort harfli Stringleri c koleysiyonundan siler,
// elemanlar String olmak zorunda, yoksa calisma aninda hata ortaya cikar
   public void dortHarflileriSil(Collection c) {
      for (Iterator i = c.iterator(); i.hasNext();)
         if (((String) i.next()).length() == 4)
            i.remove();
   }
// Alternatif cozum - biraz daha iyi gibi
   public void dortHarflileriSil(Collection c) {
      for (Iterator i = c.iterator(); i.hasNext();) {
         String s = (String) i.next();
         if (s.length() == 4)
            i.remove();
      }
   }  

Java 1.5'te Generic'ler sayesinde bu islem cok daha guvenli ve daha az kod yazilarak asagidaki sekilde gerceklestirilebiliyor. Dikkat cekilen bir nokta bu ozelligini C++'taki template ile karistirilmamasi. Goruldugu gibi yapilan sey koleksiyonun icindeki nesneleri derleyiciye onceden <String> seklinde bildiriliyor. Eger koleyksiyonda String harici bir nesne varsa derleme aninda bu hata ortaya cikiyor. Onceden bu tip hatalar calisma aninda ortaya cikiyordu.

   static void dortHarflileriSil(Collection<String> c) {
      for (Iterator<String> i = c.iterator(); i.hasNext();)
         if (i.next().length() == 4)
            i.remove();
   }  

Kodu cok sadelesmis bulmayanlariniz olacaktir, bekleyin...

2- Gelismis for dongusu

Script yazilimcilarinin alisik olduklari bir komut "foreach"'tir. Bu komut ile bir grup nesne uzerinden bastan sona tarama yapilabilir. Java 1.5'ta yeni bir komut adi eklemek yerine for dongusunu farkli kullanarak bu islemin sagladigi rahatlik kullanicilara sunuluyor. Normalde bu islem icin (yukaridaki ornekte oldugu gibi) "iterator" nesnesi kullaniliyordu. Ancak iterator kullanimi bazi durumlarda hataya yol acabiliyor. Asagidaki ornekte Java 1.5 oncesinde bir koleksiyondaki tum nesnelere nasil erisildigi gosteriliyor. iterator ve casting kullanmak mecburi.

// Java 1.4, koleksiyondaki tum zamanlayicilar iptal ediliyor.
   public void cancelAll(Collection c) {
      for (Iterator i = c.iterator(); i.hasNext();) {
         TimerTask tt = (TimerTask) i.next();
         tt.cancel();
      }
   }  

Asagida ise J2SE 1.5 ile ayni fonksiyonun gelismis for dongusu ile nasil gercekletirilecegi gosteriliyor. Ornegin ikinci parcasinda ise bir adim daha oteye gidiliyor, generics ve gelismis for dongusu beraber kullanilarak metot yaziliyor. for(TimerTask task : c) su anlama geliyor, c koleksiyonundaki nesneneleri TimerTask olarak sira ile bastan sona task degiskenine ata. Dongu icinde task degeri uzerinde istenen islem yapilir.

   // Java 1.5, gelismis for
   public void cancelAll(Collection c) {
      for (Object o : c)
         ((TimerTask) o).cancel();
   }

   // Daha da iyi, Java 1.5, gelismis for  ve generics beraber.
   public void cancelAll(Collection<TimerTask> c) {
      for (TimerTask task : c)
         task.cancel();
   }  

Sadece koleksiyonlarda degil basit dizilerde de gelismis for dongusu kullanilabiliyor

// a dizisinin toplamini dondurur, Java 1.5
int sum(int[] a) {
	int result = 0;
   for (int i : a)
	result += i;
    return result;
}

Gelismis for ve generics ozellikle iteratorlerin belaya yol actigi ic ice dongulerde buyuk kolaylik sagliyor. Koleksiyon nesnelerine erisim yapilan ic ice donguler genellikle hataya aciktir. Asagida Java 1.5 oncesi bir kullanim gosterilmistir.Bu uygulamada bir oyun kagit destesi olusturulmaya calisiliyor. ilk yaklasimda calisma ani hatasi ortaya cikiyor ve bu hatanin olusacagini kestirmek tecrube gerektirir. Cunku i iteratoru ikinci dongu icinde j iteratoru ile birlikte arttiriliyor ve i'nin sinir degeri asildiginda sistem hata veriyor.Bu yuzden kodun ikinci kisminda yer alan atama islemini yapmak zaruri.

	List tipler= ...;
   List degerler= ...;
   List Deste= new ArrayList();

   // kod1, hata - throws NoSuchElementException!
   for (Iterator i = tipler.iterator(); i.hasNext(); )
        for (Iterator j = degerler.iterator(); j.hasNext(); )
          Deste.add(new Card(i.next(), j.next()));

   // kod2, hata duzeltildi ama cirkin
   for (Iterator i = tipler.iterator(); i.hasNext(); ) {
      Tip tip = (Tip) i.next();
      for (Iterator j = degerler.iterator(); j.hasNext();)
         Deste.add(new Card(tip, j.next()));
   }

Java 1.5 ile bu islem cok daha temiz bicimde hallediliyor.

   for (Tip tip : tipler)
      for (Deger deger : degerler)
          Deste.add(new Card(tip, deger));  

3- Autoboxing - Unboxing

Onceden Collection icerisine ilkel nesnelerin yerlestirilemedigini (int, float gibi) soylemistim, bu ilkelleri koleksiyonlara eklemek icin once onlari nesne formlarina atamaniz gerekiyordu. Asagida ornekte main fonksiyona string olarak gonderilen ama aslinda integer deger ifade eden argumanlar olarak gonderilen parametreler oldugu gibi bir int degiskenin once Integer nesnesine donusturulmesi gerektigi gibi. Asagidaki yazilim komut satirindan arguman olarak girilen kelimelerin kullanim sIkligini bir tabloya kaydeder.

<code>
   public class Freq {
      private static final Integer ONE = new Integer(1);

      public static void main(String[] args) {
         // Maps word (String) to frequency (Integer)
         Map m = new TreeMap();
         for (int i = 0; i < args.length; i++) {
            Integer freq = (Integer) m.get(args[i]);
            m.put(args[i], (freq == null ? ONE :
                    new Integer(freq.intValue() + 1)));
         }
         System.out.println(m);
      }
   }  

J2SE 1.5 ozellikleri kullanilarak (generics, gelismis for ve autoboxing) ayni sinif su sekilde gerceklestirilebiliyor.

   public class Freq {
      public static void main(String[] args) {
         Map<String, Integer> m = new TreeMap<String, Integer>();
         for (String word : args)
            m.put(word, Collections.getWithDefault(m, word) +  1);
         System.out.println(m);
      }
   }  

4- Typesafe Enum

Java'da en cok karsilasilan ve eksikligi hissedilen ozelliklerden birisi C ve C++'ta sikca kullanilan enum operatorudur. Aslinca C tipi enumlar kullanilmasi son derece guvensiz yapilardir. enum sabit degerli bir dizi olusturulur. En cok kullanilan ama kullanilmasi onerilmeyen integer sabitler (C'de oldugu gibi) genellikle java'ya baslayanlarin ilk basvurdugu yontemdir. bu tip enum su nedenlerden oturu sakincalidir.

   public class Almanak {
      public static final int MEVSIM_KIS = 0;
      public static final int MEVSIM_BAHAR = 1;
      public static final int MEVSIM_YAZ = 2;
      public static final int MEVSIM_SONBAHAR = 3;
      ....
   }  

javada guvenli enum kullanimi icin ciddi tasarim yapmak gerekebiliyordu. Sirf enum siniflari olusturmak icin IDE yazilimlarinda ozel araclar bile kullaniliyor. Normalde guvenli bicimde hakkini vererek gerceklestirmek icin sayfa boyu kod gerektirebilecek oyun kagidi destesi olusturma islemi Java 1.5 typesafe enum, generics ve gelismis for ile asagidaki sekilde kolayca gerceklestirilir. asagida goruldugu gibi sadece enum Tip { maca, sinek, karo, kupa} diyerek dortlu bir kume olusturuluyor. Bu degerler ancak Tip sinifina ait nesnelere atanabilir oldugundan hatali kullanim ihtimali cok dusuktur. Kullanimi da C ve C++'a benzediginden programcilar yabancilik cekmeyecektir. Bu ifadelerin bir switch-case blogunda kullanilmasi da mumkun (bu onceden kodla tasarlanan guvenli enum siniflari icin mumkun degildi)

   enum Tip { maca, sinek, karo, kupa }
   enum Deger {ikili, uclu, dortlu, besli, altili, yedili,
              sekizli, dokuzlu, onlu, vale, kiz, papaz, as }
   // desteye kartlari ekle
   List<Kart> deste = new ArrayList<Kart>();
   for (Tip tip : Tip.VALUES)
        for (Deger deger : Deger.VALUES)
           deste.add(new Kart(Tip, Deger));
   // desteyi karistir
   Collections.shuffle(deste);  

Baska bir ornek, bu defa enum sinif oalrak ifade ediliyor. icindeki bilesenlere deger atanabiliyor. Goruldugu gibi sebze enum sinifinda hem sebzeler, hem sebzelerin fiyatlari yuklenebiliyor. Ayrica bu sinifi kullanan yazilimin ikinci parcasinda enum sinifinin switch blogunda nasil kullanilacagi gosteriliyor.

   public enum Sebze {
      domates(500), salatalik(550), biber(1000), patlican(700);
      Sebze( int fiyat) {  this.fiyat = fiyat;  }
      private final int fiyat;
      public int fiyat () {  return fiyat; }
   }  



   public class SebzeTest {
      public static void main(String[] args) {
         for (Sebze s : Sebze.VALUES)
         System.out.println(s + ": \t"
                 + s.value() + "bin TL \t" + renk(s));
      }

      private enum SebzeRengi { kirmizi, yesil, mor }

      private static SebzeRengi renk(Sebze s) {
         switch (s) {
            case domates:
               return SebzeRengi.kirmizi;
            case patlican:
               return SebzeRengi.mor;
            case salatalik:
            case biber:
               return SebzeRengi.yesil;
            default:
               throw new AssertionError("Bilinmeyen sebze: " + s);
         }
      }
   }  

5- Vararg

C ve C++'ta kullanilan elipsis adi verilen bir kavram vardir. Elipsis ile bir fonksiyona sayisi belirsiz giris parametresi gonderilebilir.Java'da bu islem icin dizi kullanilabilir ama genellikle parametre gonderilmeden dizinin hazirlanmasi yazilimcilarin hoslanmadigi bir istir. Ozellikle println gibi fonksiyornlarda elipsis tarzi bir kullanim zaman kazandirabilir dusuncesi ile J2SE 1.5'e bu ozellik varargs adi ile eklenmis.Asagida giris yapisi belirsiz bir metod icin bir parametre dizisi olusturulma isleminin JAva 1.5'ten once nasil yapildigini gosteren kod gosteriliyor. Once mecburen bir Object dizisi olusturmak gerekiyor.

   Object[] arguments = {
      new Integer(7),
      new Date(),
      "bir tunch tas, has hosh hoshaf"
   };
   String result = MessageFormat.format(arguments);  

Java 1.5 ile bu islem kolaylasiyor. public static String format(String pattern, Object... arguments) seklinde format fonksiyonuna varargs gonderilebileceginin belirtilmesi gerekiyor.

   String result = MessageFormat.format(7, new Date(), "bir tunc tash, has hosh hoshaf");  

6- Static Import

Java'ya ilk baslayanlarin biraz bocaladigi bir konu C ve C++'taki #define ve const kavramlarinin olmayisidir. Ozellikle sabit degerli verilerin kullanimi konusunda genellikle java'nin yaklasimi ilk baslandiginda cok begenilmez (Acikcasi bana gore hava hostu ama bazi durumlarda her sabitin basina sabitin tutuldugu sinifin yazilmasi biraz bunaltici olabiliyor). Static import sayesinde Java 1.5'te sabitlerin kullanimi kolaylasiyor. Asagidaki ilk ornek Java'da kullanilmamasi mumkun olan ama hic tavsiye edilmeyen bir yaklasimi gosteriyor.

// "Sabit Interface" antipatterni - kullanmayin
public interface Fizik {
  public static final double AVOGADRO_SAYISI = 6.02214199e23;
  public static final double BOLTZMANN_SABITI = 1.3806503e-23;
  public static final double ELEKTRON_KUTLESI = 9.10938188e-31;
}

public class Yogurt implements Fizik {
    public static void main(String[] args) {
        double mol = ...;
        double molekulSayisi = AVOGADRO_SAYISI * mol;
        ...
    }
}  

Oncelikle sabitlerin interface icerisinde tanimlanmasi sakincali. Sinif icerisinde static final olarak tanimladiktan sonra JAva 1.5'te static import asagidaki sekilde kullaniliyor.Onceden sabite erismek icin Fizik.AVOGADRO_SAYISI seklinde kullanmak gerekiyordu.

import static org.iso.Fizik.*;

class Yogurt {
    public static void main(String[] args) {
        double molecules = AVOGADRO_SAYISI * mol;
        ...
    }
}  

Ayrica sadece sabitleri degil statik metotlarida benzeri sekilde kullanmak mumkun. Ornegin x = Math.cos(Math.PI * theta); yerine x = cos(PI * theta); kullanmak gibi.Benzer sekilde enum sinifindaki bilesenlere de static import edildiginde dogrudan yazarak erisim mumkun.

7- Metadata

Metadata ozellikle sunucu tarafi yazilimlar ile ilgili. Bazi durumlarda istemci icin hem bir interface hem de bu interface'i kullanan bir gercekleme yazmak gerekiyordu. Asagidaki ornekte JAX-RPC ile gerceklestirilen bir web servisinden bir parca yer aliyor.

public interface CoffeeOrderIF extends java.rmi.Remote {
    public Coffee [] getPriceList()
        throws java.rmi.RemoteException;
    public String orderCoffee(String name, int quantity)
        throws java.rmi.RemoteException;
}

public class CoffeeOrderImpl implements CoffeeOrderIF {
    public Coffee [] getPriceList() {
        ...
    }
    public String orderCoffee(String name, int quantity) {
        ...
   }
}  

java 1.5'te hangi metotlarin uzak cagri icin kullanilacagini belirtmek icin fazladan bir interface yazmak yerine metotlarin basina @Remote yazmak yetiyor.

import javax.xml.rpc.*;

public class CoffeeOrder {
    @Remote public Coffee [] getPriceList() {
        ...
    }
    @Remote public String orderCoffee(String name, int quantity) {
        ...
    }
}

Sonuc

Dunyanin ozellikle sunucu ve kurumsal alandaki en populer yazilim dili ve teknoloji platformu olan java, script dillerinin yayginlasmasi ve .Net ve C#'in ortaya cikisi ile dil ozellikleri yonunden cesitli elestirilere maruz kalmisti. Java'nin bu elestirilere cevabi Java 1.5 Tiger ile veriliyor. Usta java yazilimcilarinin bir kismi yeni dil eklentilerinin dilin kullanimini kolaylastirsa da kodun anlasilabilirligini azalttigi ve gerekli olmadigi yonunde gorus belirtse de genel olarak bu eklentilerin cogunluk java kullanicilari tarafindan oldukca iyi karsilandigi soylenebilir. J2SE 1.5'in final surumunun 2004 baharinda cikmasi bekleniyor. J2SE 1.5'in islevsel ,gorunus ve performans acisindan buyuk yenilikler getirdigi de biliniyor ama henuz detaylar aciklanmadigindan bu konudaki bilgileri zamani geldiginde anlatmaya calisacagim.

Kaynaklar

Erişim

İçindekilerGirişİndex
YukarıİlkÖncekiSonrakiSon
Geriİleri
Yazdır