Java Dersleri 18 – Network Programlama – UDP

Bu makalede Java’nın network programlama kabiliyetlerinden bahsedeceğim. UDP protokolü uygulamalar arasında datagram adı verilen paketler aracılığıyla haberleşme sağlar. Bu protokol gönderilen paketlerin karşı tarafa gönderilip gönderilmemesi konusunda garanti vermediği gibi paketlerin gönderim sırasında alınmasını da garanti etmez. Herhangi bir datagram paketi gönderebilmek için bir adrese ve port numarasına ihtiyaç duyarsınız. Adres bilgisi paketin ağ üzerinde hangi bilgisayara gönderileceğini belirlerken port bilgisi ise o paketin hangi uygulama için gönderildiğini saptar. Ağ üzerinden haberleşme kabiliyetine sahip uygulamalar genellikle istemci-sunucu yapısına sahiptir. Veri akışı istemcinin sunucuya herhangi bir istek göndermesiyle başlar. Sunucu ise sürekli kendine gelen isteklere cevap verir. Dolayısıyla bu tarz uygulamalar geliştirilirken istemci ve sunucu tarafı koordineli bir şekilde geliştirilir.
(daha fazla…)

Java Dersleri 17 – JDBC API (Veritabanı Bağlantısı)

Bu makalede Java’nın veritabanı kabiliyetlerinden bahsedeceğim. Java’nın tüm veritabanlarına ulaşmak için kullandığı ortak bir API vardır. JDBC (Java Database Connectivity ) API uygulamamızı arka taraftaki veritabanı sisteminden soyutlamamıza olanak tanır. Bunu yapabilmek için elimizde bağlanmak isetdiğimiz veritabının JDBC sürücüsü olmalıdır. Örneğin HSQLDB bağlantısı yapmak istiyorsak bu veritabanı yönetim sistemine ait JDBC sürücüsünü içeren JAR dosyasını projemize eklemeliyiz. Daha sonra bu JAR dosyası içinde bulunan driver sınıfını proje içindeyken JVM’e yüklenmesini sağlamalıyız. (daha fazla…)

Swing Programlama : JFileChooser

Bu derste Java swing arayüzlerimizden sistemimizdeki dosya sistemine erişimi sağlayan JFileChooser sınıfının detaylarını anlatmaya çalışacağım. İlk olarak en temel haliyle bir JFileChooser diyalog penceresi nasıl açılır onu görelim :

 JFileChooser jfc = new JFileChooser();
 jfc.showOpenDialog(null);

Bu kod parçacığı kullanıcının ön tanımlı dizinini gösteren bir dosya diyaloğu açar. Ön tanımlı dizininizi linux ortamında komut satırına “env” komutunu vererek ulaşabilirsiniz. Bu komutu çalıştırdığınızda karşınıza gelen listedeki HOME ortam değişkeni kullanıcının ön tanımlı dizinidir. Örnek görüntümüz şu şekilde olacaktır :

JFileChooser Öntanımlı Klasör

JFileChooser Öntanımlı Klasör


Peki biz dosya diyalogumuzu öntanımlı klasörde değil de başka klasörde açmak istersek ne yapmalıyız? Bunun için JFileChooser sınıfının parametre olarak dosya yolu yada dosya alan diğer yapılandırıcı metodunu kullanmalıyız. Örneğin ben dosya seçme diyaloğumu “/home/orhan/Downloads” klasöründe açmak istersem şu kod parçasını kullanmam gerekir :

JFileChooser jfc = new JFileChooser("/home/orhan/Downloads");
 jfc.showOpenDialog(null);

Bundan sonra ihtiyacımız olan kullanıcının hangi seçeneği seçtiğini öğrenmek. Kullanıcı herhangi bir dosyayı seçebilir veya işlemi iptal edebilir. Diyalogdan kullanıcı çıktısını şu şekilde alıyoruz :

JFileChooser jfc = new JFileChooser("/home/orhan/Downloads");
int kullaniciSecimi = jfc.showOpenDialog(null);

Kullanıcı seiçimi değişkeninin alabileceği değerler de JFileChooser sınıfında tanımlanmıştır. Bu değerler :

JFileChooser.APPROVE_OPTION    //seçim onaylandı
JFileChooser.CANCEL_OPTION       //seçim iptal edildi
JFileChooser.ERROR_OPTION        //işlem sırasında hata oluştu

Şimdi kullanıcının seçmiş olduğu dosya ismini JFileChooser sınıfından almayı öğrenelim.

if (kullaniciSecimi == JFileChooser.APPROVE_OPTION) {
    System.out.println(jfc.getSelectedFile());
}

Kullanıcı tarafından seçilen dosya referansına ulaşmak için getSelectedFile() metodunu kullanıyoruz. Eğer kullanıcıya birden fazla dosya seçme imkanı tanımak istiyorsak sırasıyla şu işlemleri yapmalıyız.

jfc.setMultiSelectionEnabled(true);
 int kullaniciSecimi = jfc.showOpenDialog(null);
 if (kullaniciSecimi == JFileChooser.APPROVE_OPTION) {
     for(File f : jfc.getSelectedFiles()) {
         System.out.println(f);
     }
}

Son olarak seçimimiza filtre eklemeyi öğrenelim. Örneğin sadec zip uzantılı dosyaların seçilebilmesini istiyorsak :

 jfc.setFileFilter(new FileFilter() {
            @Override
            public boolean accept(File f) {
                if(f.isDirectory())
                    return true;
                String fileName = f.getName();
                int nokta = fileName.lastIndexOf('.');
                String ext = "";
                if(nokta > 0)
                    ext = fileName.substring(nokta+1);
                return ext.equalsIgnoreCase("zip");
            }

            @Override
            public String getDescription() {
                return "ZIP Dosyaları";
            }
        });

Yeni bir filtre eklemek için setFileFilter metodundan faydalandık. Bu filtremizde kullanıcının klasörleri ve zip uzantılı dosyaları seçebilmesine izin verdik. Dosya uzantısını saptayabilmek için String sınıfının lastIndexOf ve substring metodlarından yararlandık.

Java Dersleri 16 – Enum Yapısı

Java da enum yapıları 1.5 versiyonuyla birlikte gelmiştir. Bu versiyondan önce enum gereksinimi static final int değişkenlerle giderilmekteydi. Bu yaklaşımın tip güvenliği yoktur yani enumlar herhangi bir int, double vs değerle karşılaştırılabilirler, herhangi bir int değere eklenebilirler. Bunun yanında grup olarak kullandığınız bu int değişkenleri sırayla gezemezsiniz. Oysa ki enumlarda bu aranan bir özelliktir. Bunun gibi bir kaç yan etkiden dolayı Java’nın 1.5 versiyonuyla birlikte enum’lar dile eklendi. Java enumları sınıflara benzemekle birlikte çoğu özelliği kısıtlanmıştır. Öncelikle basit bir Enum tanımı ve kullanımı görelim :

 enum AminoAsit{ALANIN,GLUTAMIN,PROLIN,SERIN};

Java’da Enum tanımlamak için enum anahtar kelimesi kullanılır. Daha sonra enum elemanları süslü parantez içinde yazılır. Şimdi bu örneği biraz daha geliştirelim ve enum için bir yapıcı (constructor) metod tanımlayalım :

 enum AminoAsit {
        ALANIN("apolar"), GLUTAMIN("polar"), PROLIN("nötür"), SERIN("nötür");
        public String polarite_;
        AminoAsit() {
        }
        AminoAsit(String polarite) {
            polarite_ = polarite;
        }
    };

Örneği biraz değiştirerek bir String alan yapıcı metodumuzu ekledik. Burada dikkat etmemiz gereken kural yapıcı metodumuzun public erişim seviyesinde olmaması. Enum’ların sınıflardan bir farkı yapıcı metodlarının public erişim seviyesinde olamamasıdır. Enum yapılarının sınıf yapısından bir diğer farkı ise Enum yapılarının herhangi bir sınıftan miras alamamasıdır. Bunun tersine Enum yapıları herhangi bir arayüzü gerçekleyebilirler yani şu kullanım geçerlidir :

interface Hidropatik {
        public double getHidropatiKatsayi();
    }
    enum AminoAsit implements Hidropatik {
        ALANIN("apolar") {
            @Override
            public double getHidropatiKatsayi() {
                return 1.8;
            }
        },
        GLUTAMIN("polar") {
            @Override
            public double getHidropatiKatsayi() {
                return -3.5;
            }
        },
        PROLIN("nötür") {
            @Override
            public double getHidropatiKatsayi() {
                return 0.0;
            }
        },
        SERIN("nötür") {
            @Override
            public double getHidropatiKatsayi() {
                return -0.8;
            }
        };
        public String polarite_;
        AminoAsit() {
        }
        AminoAsit(String polarite) {
            polarite_ = polarite;
        }
    };

Yukarıda tanımladığımız Enum’u nasıl kullanacağımızı görelim. Aşağıdaki örnekte tanımladığımız Enum’un tüm elemanlarına ulaşıyoruz:

 for (AminoAsit a : AminoAsit.values()) {
            System.out.println(a.name() + " " + a.polarite_ + " " + a.getHidropatiKatsayi());
        }

Java Dersleri 15 – Koleksiyon API (Collection API) Map

Map arayüzü anahtar-değer ikililerini bir arada tutmak için tasarlanmıştır. Matemetikteki fonksiyonların yazılım tarafında karşılığı olan map veri yapıları yazılım mimarisinde sıkça kullanılır. Örneğin yazılımımızda bulunan nesnelere birer kimlik numarası vererek bu numara ile nesne arasında anahtar-değer ilişkisi kurabiliriz. Böylelikle istediğimiz nesneye kimlik numarası aracılığıyla rahatlıkla erişebiliriz. Java Map arayüzü herhangi bir sıralama kısıtı getirmez. Map’e eklenen anahtar-değer ikililerinin eklendiği sırada kalacağı garanti değildir. Map arayüzünü gerçekleyen sınıflar arasında en bilineni HashMap sınıfıdır. HashMap verilen anahtardan hash fonksiyonu yardımıyla bir array indeksi oluşturur. Verilen değer de bu array indeksindeki belleğe yerleştirilir. Hash fonksiyonları çok temel matematiksel işlemler kullandıklarından hızlıdırlar. Dolayısıyla HashMap’de verilere erişim sabit zamanda olur. HashMap performansı için önemli olan iki parametre ilk kapasite ve yük faktörüdür. Varsayılan olarak ilk kapasite 11′dir. Yük faktörü HashMap koleksiyonumuzun herhangi bir anda maksimum doluluk oranını ölçer. Bu değer varsayılan olarak %75 dir. HashMap’de doluluk oranı bu değerin üzerine çıktığında kapasite arttırımına gidilerek değerler tekrar hash’lenir. Şimdi bir örnekle Map veri yapısına eleman eklemeyi ve geri almayı görelim :

package net.orhanbalci.collections;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class HashMapExample {

    public static void main(String[] args) {
        Map<Integer,String> m = new HashMap<Integer,String>();

        for (int i = 0; i < 10; i++) {
            m.put(i, String.valueOf(i) + " değer");
        }

        Set<Integer> ks = m.keySet();

        Iterator<Integer> i =  ks.iterator();

        while (i.hasNext()) {
            Integer key = i.next();
            System.out.print(key + " ");
            System.out.println(m.get(key));
        }
    }
}

Örneğimizde 11. satırda yeni bir HashMap nesnesi tanımlıyoruz. Java’nın generics özelliğini (şablon sınıflar) kullanılarak anahtarların veri tipini Integer değerlerin veri tipini ise String olarak belirttik. 14. satırda Map arayüzünün put() metodunu kullanarak HashMap koleksiyonumuza yeni eleman ekliyoruz. 24. satırda ise get() metodu yardımıyla HashMap koleksiyonumuzdan anahtar yardımıyla değerimize ulaşıyoruz.

Yukarıda bahsettiğimiz ilk kapasitenin performansa olan etkisini başka bir örnekte görelim :

        Map<Integer,String> m2 = new HashMap<Integer,String>(10);
        Map<Integer,String> m3 = new HashMap<Integer,String>(100);

        long time1 = System.currentTimeMillis();
        for (int k = 0; k < 10000; k++) {
            m2.put(k, String.valueOf(k) + " değer");
        }
        long time2 = System.currentTimeMillis();
        System.out.println(String.valueOf(time2-time1) + " milisaniye");

        time1 = System.currentTimeMillis();
        for (int k = 0; k < 10000; k++) {
            m3.put(k, String.valueOf(k) + " değer");
        }
        time2 = System.currentTimeMillis();
        System.out.println(String.valueOf(time2-time1) + " milisaniye");

Bu örneğimizde ise iki adet HashMap nesnesi oluşturuken ilk kapasiteyi yapılandırıcı metoda parametre olarak veriyoruz. m2 koleksiyonumuzun ilk kapasitesi 10 iken diğerinin ilk kapasitesi 100 dür. Her iki koleksiyona arka arkaya 10000 anahtar-değer ikilisi ekleyip performansı ölçtüğümüzde ilk kapasitesi 10 olan koleksiyona ekleme işlemi 46-47 milisaniye sürerken ilk kapasitesi 100 olan koleksiyona ekleme işlemi 19-20 milisaniye sürmekte. Görüldüğü üzere kapasite artırımına gitmek zaman kaybına neden olmaktadır.

Ulusal Bilgisayar Olimpiyadı 2009 – Soru 36

Soru metni için öncelikle 40. soruda verdiğimiz açıklamaları okuyun.
‘i3(3(<)i)’ komutu kaç numaralı şekli çizer?
A) (1)
B) (6)
C) (9)
D) (10)
E) (14)

CEVAP: Nispeten kolay bir soru. Komutu incelersek ilk olarak kuzeye ilerleyip daha sonra 3 kere 135 derece sola dönüp ilerlemeliyiz.

Soru 36

Soru 36

Yukarıdaki şekilden takip edersek önce kuzeye yani 1′den 2′ye. Daha sonra sola 135 derece dönüp ileriye. Yani 2′den 3′e. Yine 135 derece sola dönüş ve ilerleme : 3′den 1′e. Son kez 135 derece sola ve ileri : 1′den 4′e. Doğru cevap C) (9)

Java Dersleri 14 – Koleksiyon API (Collection API) Kuyruklar (Queue)

Koleksiyon API’sine ait diğer bir arayüz kuyruk (queue) arayüzüdür. Temel olarak listeye benzemekle birlikte listelerden farkı elemanlarını farklı bir şekilde sıralamasıdır. Kuyruk her zaman olmamakla birlike elemanlarını FIFO (ilk giren ilk çıkar) mantığıyla dizerler. Bunun farklı olduğu durumlar da mevcuttur. Örneğin PriorityQueue (Öncelik Kuyruğu) içindeki elemanları neye göre karşılaştıracağını kullanıcıya sorar. Eğer kullanıcı tarafından bir karşılaştırma yöntemi belirtilmezse doğal sıralama yöntemlerini kullanır. Örneklerle kuyruk arayüzünü tanıyalım :

        Queue<String> q = new LinkedList<String>();
        for (int i = 0; i < 10; i++) {
            q.offer(String.valueOf(i));
        }
        for (int i = 0; i < 10; i++) {
            System.out.println(q.poll());
        }

Bu örnekte bir kuyruk yapısına String olarak 0′dan 10′a kadar olan sayılar önce eklenmiş daha sonra eklendiği sırada çıkarılmıştır. Kuyruğa eleman eklemek için offer() metodunu kullanıyoruz. Aynı iş için add() metodu da mevcuttur. Farkları ise ekleme işlemi başarısız olduğu zaman offer() metodu null değeri dönerken add() metodu istisnai durum fırlatır. Kuyruğun başındaki elemanın değerini alarak kuyruktan kaldırmak için ise poll() metodunu kullanıyoruz. offer() metodunda olduğu gibi poll() metodu için de farklı bir versiyon olan remove() metodu bulunur. Farkları yine başarısız olma durumundaki davranışlarıdır. Kuyruk veri yapısından sıradaki elemana ulaşmak için peek() metodu kullanılır. Bu metod sıradaki elemanı kullanıcıya verir fakat kuyruktan silmez. Şimdi de FIFO’dan farklı bir sıralama yöntemiyle çalışan kuyruk örneği yazalım. Yazacağımız örnek kelimeleri içerisindeki sesli harf sayısına göre kuyrukta tutsun. Yani içinde daha fazla sesli harf olan kelime kuyrukta önde yeralsın :

        PriorityQueue<String> pq = new PriorityQueue(15, new Comparator() {
            public int compare(Object o1, Object o2) {
                if ( o1 instanceof String && o2 instanceof String)
                {
                    String s1 = (String) o1;
                    String s2 = (String) o2;
                    int vowels1 = s1.replaceAll("[^aeıioöuü]", "").length();
                    int vowels2 = s2.replaceAll("[^aeıioöuü]", "").length();
                    return vowels2 - vowels1;
                }
                return 0;
            }
        });

Örneğimizde kullanıcı tarafından tanımlanmı isimsiz bir Comparator nesnesini kullanarak bir PriorityQueue oluşturuyoruz. Comparator nesnemiz iki String’i içindeki sesli harf sayısına göre karşılaştırmaya yarıyor. Sesli harf sayısını bulmak için String sınıfının replaceAll() metodunu kullanıyoruz. Bu metod verilen düzenli ifadeyi, ikinci parametresiyle değiştirir. Şimdi oluşturduğumuz PriorityQueue nesnesine elemanlar ekleyelim ve sonucu görelim :

        pq.offer("iğne");
        pq.offer("iplik");
        pq.offer("bilgisayar");
        pq.offer("masa");
        pq.offer("sandalye");

        while(!pq.isEmpty())
        {
            System.out.println(pq.remove());
        }

En çok sesli harf “bilgisayar” kelimesinde olduğu için kuyruğun başında yer alacaktır. Daha sonra sırasıyla “sandalye”, “masa” , “iğne” , “iplik” kelimeleri gelecektir.