29 Eylül 2011 Perşembe

İşinize Yarayabilecek Hizmet Kitaplıkları

Bu yazıda Java projelerinizde kullanmak isteyebileceğiniz ve çeşitli amaçlarla işinizi oldukça kolaylaştırabilecek Java hizmet kitaplıklarından bahsedeceğiz. İşte onlardan bazıları:
  • Google Guava: Google tarafından geliştirilmiş ve çeşitli amaçlara yönelik paketler sunan bir Java hizmet kitaplığıdır. Guava'daki paketleri aşağıdaki gibi özetleyebiliriz: 
    • temel (.base): Java genelinde hizmet sınıfları sunar. Bu sınıflar arasında karakter katarı (String) işlemleri, istisnai durum yönetimi (exception handling) gibi dil özelliklerini kolaylaştıran sınıflar bulunmaktadır. 
    • koleksiyonlar (.collect): Java koleksiyon sınıflarını (List, Set, Map) genişleten özel koleksiyon yapıları sunmaktadır. Ayrıca koleksiyonlar üzerinde işlem yapılmasını kolaylaştırmak üzere birtakım sınıflar sağlamaktadır (örn: Lists, Sets, Maps, Iterators vb.).
    • girdi-çıktı (.io): Java I/O kitaplığı ile kolay çalışmayı sağlayacak hizmet sınıfları sunmaktadır. Özellikle girdi-çıktı akışları (input-output stream) ve dosyalar arasında veri kopyalama işlemlerini oldukça kolaylaştıran işlevler bulunmaktadır. Örneğin, copy(InputStream from, OutputStream to) metodu ile bir girdi akışından okunan veri doğrudan bir çıktı akışına aktarılabilir.
    • eşzamanlılık (.concurrent): Java'da eşzamanlı programlamayı kolaylaştırmak üzere kapsamlı bir kitaplık sunar.
    • Bahsedilen bu paketler dışında Guava, matematik işlemleri, ilkel tip işlemleri ve yayın-abonelik (publish-subscribe) iletişimi için de paketler sunmaktadır.
  • Apache Commons: Guava gibi Apache Commons'da Java'yı birçok yönden genişleten ve dolayısıyla geliştiren bir hizmet kitaplığıdır. Guava'dan çok daha geniş bir içerik sunan Apache Commons, işlev bazında ayrı ayrı paketlenmiştir. Bu nedenle tüm kitaplığı projenize indirmek yerine ihtiyaç duyduğunuz paketi alıp kullanabilirsiniz. Apache Commons projesi tarafından sağlanan tüm paketlerin listesine buradan ulaşabilirsiniz.
  • Gson: JSON (Java Script Object Notation) metinleri ile Java nesneleri arasında dönüşüm yapmak için kullanılan bir kitaplıktır. Java nesnelerini JSON'a çevirebildiği gibi JSON metinlerinden Java nesneleri oluşturmak için de kullanılabilir. Gson, dönüşümler için Java sınıflarının Java belirtimleri (annotation) ile işaretlenmesine gerek duymaz. JsonObject, JsonArray gibi sınıflar sayesinde Java sınıflarına dönüşüme gerek kalmadan da JSON ile çalışmak mümkün olmaktadır.
  • Guice: Java'da bağımlılık iletimi (dependency injection) deseninin uygulanması için bir çerçeve sağlar. @Inject belirtimi ile sınıflar arasındaki bağımlılığı azaltarak daha kolay değiştirilebilir, test edilebilir ve yeniden kullanılabilir kod yazılmasını sağlar. 
  • Joda-Time: Java tarih-zaman sınıfları yerine kullanılabilecek güçlü bir hizmet kitaplığıdır. Joda-Time, dayOfYear, hourOfDay gibi basit sahalar ile önemli tarihsel bilgileri hızlıca elde etmemizi sağlarken sunduğu hizmet sınıfları ile karmaşık tarih işlemlerini kolayca yapabilmemize olanak verir. Yaygın olarak kullanılan kitaplık şu an için (sürüm 2.0) 8 takvim sistemini desteklemektedir.
  • XStream: Java nesnelerini XML'e serileştirmek ve XML belgelerinden Java nesnelerini okumak için kullanılan güçlü bir kitaplıktır. XStream ile birçok nesne herhangi bir eşleme bilgisine (mapping) gerek duymadan XML'e serileştirilebilir.
  • log4j: İyi bilinen ve Java projelerinde oldukça yaygın kullanılan bir günlükleme (logging) kitaplığıdır.
  • logback: log4j projesinin takipçisi olarak geliştirilen bu proje log4j'nin eksik kaldığı noktaları geliştirmektedir. Başarım ve testler açısından log4j'ye göre üstünlük gösteren logback'in diğer üstünlüklerine buradan ulaşabilirsiniz.
  • SLF4J: SLF4J (Simple Logging Facade for Java), java.util.logging, Log4J, Jakarta Commons Logging ve logback gibi seçkin günlükleme kitaplıkları için bir arayüz ve soyutlama sağlar. Böylece kullanıcılar altta kullanılan günlükleme kitaplığını, dağıtım anında bile, kolayca değiştirebilirler.
  • Mockito ve EasyMock: Bu iki kitaplık birim testler sırasında henüz gerçekleştirilmemiş Java arayüzlerinin davranışlarını taklit edebilmemizi ve böylece testlerin yazılımın erken aşamalarında bile yazılmasını sağlar.   


intern() ile String karşılaştırmaları

Malum String' Java'da primitif bir tip olarak tanımlı değil. Object sınıfından türetilmiş, bir sürü metodu native olan final bir sınıf. Yani hiyerarşisinin sonunda yer alıyor. Siz herhangi bir sınıf türetemiyorsunuz.

Java'da bildiğimiz gibi == operatörü ile primitif tipler dışındaki karşılaştırmalar obje referansı karşılaştırmaları. Objeler üzerinde karşılaştırma yapmak için equals() methodu kullanılıyor, String'de olduğu gibi.

String içinde yer alan metodları incelerken String döndüren intern() metoduna herkesin gözü gitmiştir. Peki nedir bu intern?

intern() temel olarak şu işe yarıyor, intern() metodu çağırıldığı zaman String objesinin hash'ini alıp, bir lookup tablosuna bakıyor, eğer String objesi ile aynı içeriğe sahip bir başka obje varsa bunu döndüyor. Böylece equals() metodu ile kontrol yapmadan direk lookup table'da arayarak karşılaştırma yapılabiliyor.

Ayrıca JVM statik durumdaki String ifadeleri otomatik olarak intern() işleminden geçiriyor. Böylece == ifadesi ile kontrol yapılabiliyor. Böylece iki String'in içeriklerinin tek tek kontrol edilmesi yerine direk obje referansları kontrol edilmiş oluyor yani doğal olarak equals() metoduna göre oldukça hızlı bir karşılaştırma yapılabiliyor.

Aşağıdaki kodu çalıştırdığınızda tüm ifadeler statik olduğu için == operatörü ile karşılaştırmaların çalıştığını görebilirsiniz.





 1 import java.io.BufferedReader;
2 import java.io.IOException;
3 import java.io.InputStreamReader;
4
5 public class StringIntern {
6
7 public static final String CONSTANT_STRING = "string";
8 public static void main(String[] args) throws IOException {
9 String str1 = "string";
10 if(str1 == CONSTANT_STRING) {
11 System.out.println("1. karşılaştırma");
12 }
13 String str2 = "string";
14 if(str1 == str2) {
15 System.out.println("2. karşılaştırma");
16 }
17
18 InputStreamReader converter = new InputStreamReader(System.in);
19 BufferedReader in = new BufferedReader(converter);
20 String str3;
21 while((str3 = in.readLine()) != null && !str3.equals("")) {
22 if(str3 == CONSTANT_STRING) {
23 System.out.println("3. karşılaştırma");
24 }
25 if(str3.intern() == CONSTANT_STRING) {
26 System.out.println("4. karşılaştırma");
27 }
28 }
29 }
30 }

23 Eylül 2011 Cuma

Genel Tipler (Generic Types) ile Değişken Dönüş Tipli Metotlar

Java'da genel tipler (generics) kullanılarak dönüş tipi çağrıldığı yere göre değişebilen kullanışlı metotlar yazılabilir. Örneğin aşağıda "nesneGetir()" metoduna yapılan her iki çağrım da sorunsuz çalışabilir ve bizi fazladan nesne dönüşüm (object casting) işleminden kurtarabilir. Halbuki aynı metottan beklenen dönüş tipi, iki satırda farklı (String ve Integer) olduğu için satırlardan birinde derleme hatası oluşması beklenirdi.

String nesne1 = yigin.nesneGetir("nesne1");
Integer nesne2 = yigin.nesneGetir("nesne2");

Bu tip bir kullanımı sağlayabilmek için genel tiplerden yararlanabiliriz. Aşağıdaki NesneYigini sınıfı içindeki "nesneGetir()" metodu örnekteki kullanımı sağlayacak şekilde tasarlanmıştır. Böylece Java derleyicisi metodun çağrıldığı yerde dönüş tipini algılayarak nesne dönüşümünü otomatik olarak yapmaktadır.

public class NesneYigini {
    private Map<String, Object> yigin;
 
    @SuppressWarnings("unchecked")
    public <T> T nesneGetir(String nesneIsmi) {
        return (T) yigin.get(nesneIsmi);
    }
}

nesneGetir() metodu kullanılırken hangi nesne ismine göre hangi tipin geleceği önceden bilinmelidir. Yani yukarıdaki örnekte "nesne1" isminin  bir String ve "nesne2"'nin de bir Integer döndüreceği önceden bilinmektedir. Aksi takdirde çalışma zamanında ClassCastException hatası ile karşılaşılacaktır.

19 Eylül 2011 Pazartesi

JQuery ile Basit bir Yayın Akışı (Feed Stream) Görünümü

Bu yazımızda JQuery kullanarak basit bir yayın akışı görünümünün (örn. Twitter'daki tweet akışı) kolaylıkla nasıl oluşturulabileceğini göreceğiz. Geliştireceğimiz uygulama bir metin kutusundan, iki düğmeden (Yayınla, Temizle) ve eklediğimiz yayınları gösteren bir listesinden oluşacak. Ayrıca yayının listeye eklenmesi sırasında hoş bir görsellik elde edilmesi için JQuery animasyonlarından yararlanılacaktır. Uygulamanın basit tutulması amacıyla sunucu taraflı bir gerçekleştirimden bahsedilemeyecektir.

Şimdi zaman kaybetmeden uygulamamızı geliştirmeye başlayalım. İlk olarak aşağıdaki basit HTML arayüzünü oluşturmalıyız. Daha önce de söz ettiğimiz gibi ekranımız kullanıcı iletisinin yazıldığı bir metin kutusundan (gonderiMetni), yazılan metni yayınlamayı sağlayan bir düğmeden (yayinla), listeye eklenen gönderileri silen bir başka düğmeden (temizle) ve yayınlanan gönderileri listeleyen bir HTML div alanından (gonderiler) oluşmaktadır. (Not: Karmaşıklığı önlemek amacıyla stil özellikleri HTML kodunda gösterilmemiştir.)
<div>
<textarea id="gonderiMetni"></textarea>
<input id="yayinla" type="button" value="Yayınla" />
<input id="temizle" type="button" value="Temizle" />
<div id="gonderiler"></div>
</div>
İkinci aşamada yayinla ve temizle düğmelerinin işlevlerini yerine getiren JavaScript fonksiyonlarını gerçekleştireceğiz. İlk olarak aşağıdaki yayınlama fonksiyonu inceleyelim. Fonksiyonun ilk satırında kullanıcı tarafından metin kutusuna girilen ileti metni alınmıştır. Bu amaçla JQuery'nin id seçicisi ("#elementId") ve seçilen ögenin degerini döndüren val() fonksiyonu kullanılmıştır. 2. satırda ise gönderilerin listeleneceği div ögesi elde edilmiştir. 3. satır gönderi metninin bir HTML div ögesi içine alındığı bölümdür. Göründüğü gibi JQuery $() fonksiyonu ile çok kolay bir şekilde HTML oluşturulabilmektedir. 4 ve 5. satırlarda oluşturduğumuz div ögesine css() fonksiyonu ile stil değerleri eklenmiştir. 6. satırda prependTo fonksiyonu kullanılarak gönderi metnini tutan div ögesi gönderi listesine eklenmiştir. Buraya kadar olan kısımda girilen gönderi başarılı bir şekilde listeye eklenebilmektedir. Ancak daha hoş bir görünüm elde etmek amacıyla 7 ve 8. satırlarda listeye ekleme işlemi bir animasyon ile zenginleştirilmiştir. hide() fonksiyonu ile div öncelikle görünmez hale getirilmiş, daha sonra da animation() fonksiyonu ile 400 mili-saniye içerisinde görünür hale getirilmiştir.
function yayinla() { 
1. var gonderiMetni = $("#gonderiMetni").val();
2. var gonderiler = $("#gonderiler");
3. $("<div>" + gonderiMetni + "</div>")
4. .css('border-bottom','1px solid #909090')
5. .css('margin-bottom', '5px').css('padding', '4px')
6. .prependTo(gonderiler)
7. .hide()
8. .animate({'opacity': 'toggle', 'height':'toggle'}, 400);  
}
Aşağıdaki temizle() fonksiyonu ile gönderi listesi ve metin kutusu temizlenmiştir.
function temizle() {
$("#gonderiler").empty();
$("#gonderiMetni").val(null);
}
Yapmamız gereken son işlem yukarıdaki fonksiyonları ilgili düğmelerin tıklanma olaylarına (click event) bağlamaktır. Aşağıdaki kod parçası ile bu işlem HTML dokümanı hazır olduğunda (document.ready()) yapılmaktadır.
$(function() {
$("#yayinla").click(yayinla);
$("#temizle").click(temizle);
});
Uygulamayı buradan deneyebilir ve ilgili HTML belgesine buradan ulaşabilirsiniz. Kolay gelsin :)

17 Eylül 2011 Cumartesi

Java'da Belirtim (Annotation) Kullanımı

Java belirtimleri Java kaynak koduna eklenen sözdizimsel üst-bilgi olarak düşünülmelidir. Belirtimler sayesinde sınıf, metot, saha gibi temel programlama yapılarını işaretlemek ve bu yapılara ek bilgi yüklemek mümkün hale gelmiştir.

Belirtimler, program akışını doğrudan etkilemezler. Fakat işaretlenmiş (üzerine bir belirtim eklenmiş) yapılara ek bilgi sağlayıp, çalışma zamanında bu yapıların ne şekilde kullanılması gerektiğini bildirebilirler. Tabi ki bunun için bu belirtimleri yorumlayıp ne yapılacağına karar veren programın da kodlanmış olması gerekir.

Kullanıcı tanımlı Java Belirtimleri
Java, JDK tarafından sağlanan belirtim tipleri dışında kendi tiplerimizi de oluşturmamıza olanak verir. Bunun için "@" işareti ile belirtilen özel bir arayüz (interface) tanımı yapılmalıdır. Örneğin, aşağıdaki kod parçasıyla @TestMetodu isimli bir belirtim oluşturup bunu test amaçlı metotları işaretlemek için kullanabiliriz (bkz. OrnekTestSınıfı.testMetodu()).

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestMetodu {
}

public class OrnekTestSınıfı {
@TestMetodu
public void testMetodu() {
System.out.println("Bu bir test metodudur.");
}
}

@TestMetodu belirtimi tanımlanırken iki üst-belirtim (meta-annotation) kullanılmıştır: @Target ve @Retention. @Target, tanımladığımız belirtimin hangi program ögelerine uygulanabileceğini ifade eder. Örneğimizdeki gibi tek bir öge tipi alabileceği gibi birden çok tipi de belirtebilir (örn. @Target({ElementType.METHOD, ElementType.FIELD})). Alabileceği değerler şöyledir (bkz. java.lang.annotation.ElementType): TYPE (sınıf ve arayüzler), FIELD (sınıf sahaları), METHOD (metotlar), PARAMETER (metot parametreleri), CONSTRUCTOR (yapılandırıcılar), LOCAL_VARIABLE (yerel değişkenler), ANNOTATION_TYPE (belirtim tanımları, üst-belirtim olarak), PACKAGE (Java paketleri).

@Retention belirtimi ise işaretlenen belirtimin Java sanal makinesi (JVM) tarafından nasıl ve ne kadar süre saklanacağını söyler ve RetentionPolicy.{SOURCE, CLASS, RUNTIME} değerlerinden birini alabilir. SOURCE ile işaretlenmiş belirtimler derleme süresince derleyici tarafından okunurlar ve üretilen Java .class dosyasında yer almazlar. CLASS (varsayılan değer) kalıcılığına sahip belirtimler ise derleyici tarafından .class dosyasına konurlar ancak çalışma zamanında erişilemezler. Son olarak RUNTIME kalıcılık politikası ile belirtimler, çalışma zamanında Java yansıma (reflection) kütüphanesi ile erişilebilir halde saklanırlar.

Belirtim Parametreleri
Java belirtimleri, Java ögelerini sadece işaretlemek için kullanılabilecekleri gibi (örn. @TestMetodu belirtimi) bu ögelere ek bilgiler yüklemek için de kullanılabilirler. Örneğin, @Yazar("ovunccetin") gibi bir belirtim ifadesi, işaretlenmiş olan Java ögesinin kim tarafından yazıldığını açıklayabilir. Bu tip, bilgi yükleyici belirtimler yapabilmek için belirtim tanımlarına parametre eklenmelidir. Aşağıdaki, @Yazar tanımında value() metodu ile belirtimin yazar ismini parametrik olarak alması sağlanmıştır (value kelimesi Java belirtimleri için özel bir kelimedir ve parametre ismi kullanmadan değer atanabilmesini sağlar. Yani, @Yazar(value = "ovunccetin") yerine doğrudan @Yazar("ovunccetin") yazılabilir. @Yazar belirtiminde value() yerine isim() diye bir parametre kullanmış olsaydık bu durumda @Yazar(isim = "ovunccetin") kullanımı zorunlu olacaktır.).

Belirtim parametrelerine varsayılan değer atanmadığı takdirde, ilgili belirtim kullanılırken bu parametrelere değer atanması zorunludur, aksi takdirde derleme hatası oluşacaktır. Örneğin, aşağıdaki @Yazar belirtiminde aciklama parametresine varsayılan değer atanmıştır. Yani, @Yazar("ovunccetin") şeklindeki kullanımda aciklama parametresi varsayılan değerini ("") alacaktır.  @Yazar(aciklama = "Açıklama...") şeklindeki kullanım ise value parametresinin varsayılan değeri olmadığından derleme hatasına yol açacaktır.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Yazar {
public String value();
public String aciklama() default "";
}

Yansıma Kütüphanesi ile Belirtimlerin Okunması
Belirtimler tek başlarına program akışına etki etmezler. Bunların geliştirici kodu tarafından okunması ve yorumlanması gerekir. Bunun için Java Yansıma (java.lang.reflect) kütüphanesi kullanılmaktadır. Bununla ilgili bir örnek aşağıda verilmiştir.

public class OrnekSinif {
   @Yazar("ovunc")
   public void method1(){}
   public void method2(){}
   @Yazar("ali")
   public void method3(){}
}

public class MetotYazdir {
public static void main(String[] args) {
   // OrnekSinif'i içindeki public metotlar...
   Method[] metotlar = OrnekSinif.class.getMethods();
   for (Method m : metotlar) {
      // Metot üzerindeki @Yazar belirtimi...
      Yazar yz = m.getAnnotation(Yazar.class);
      if (yz != null) { // Belirtim var mı?
         String msg = m.getName() + "(): " + yz.value();
         System.out.println(msg);
      }
   }
}
}

// Ekran çıktısı aşağıdaki gibi olacaktır.
method1(): ovunc
method3(): ahmet

5 Ağustos 2011 Cuma

Merhaba Dünyalı

Eclipse ortamında çalışırız. Genelde kod yazarız.
public class MerhabaDunyali {
    public static void main(String[] args) {
        System.out.println("Merhaba Dünyalı");
    }
}