Effective Java Madde 16: Kalıtım Yerine Komposizyonu Tercih Edin

Nisan 27th, 2017 No comments

Kalıtım kodların yeniden kullanımını sağlayabilen güçlü bir araçtır, ancak her zaman yapacağınız iş için en doğru araç olmayabilir. Yanlış kullanıldığında kırılgan yazılımlara yol açar. Kalıtımı, aynı paket içerisinde, ata sınıf ve çocuk sınıfın aynı programcının kontrolünde olduğu durumlarda kullanmak güvenlidir. Bunun yanında, özellikle kalıtılmak için tasarlanmış ve belgelenmiş sınıfları kalıtmak da güvenlidir (Madde 17). Ancak, farklı paketlerdeki sıradan somut sınıfları kalıtmak tehlikelidir. Hatırlatma olarak söyleyelim, burada kalıtım dediğimiz zaman bir sınıfın başka bir sınıfı kalıtmasından bahsetmekteyiz. Bahsedilen problemler arayüz (interface) kalıtırken geçerli değildir.

Metot çağırmanın aksine, kalıtım yapmak sarmalamayı (encapsulation) ihlal eder. Başka bir deyişle, bir çocuk sınıf işlevini gerçekleştirebilmek için ata sınıfın gerçekleştirim detaylarına bağımlıdır. Ata sınıfın içeriği zaman içerisinde yeni sürümlerle birlikte değişebilir, ve bu durumda çocuk sınıfın kodu hiç değişmemiş olsa bile çalışmayabilir. Sonuç olarak, eğer ata sınıf özel olarak kalıtılmak için tasarlanmamışsa, çocuk sınıf değişikliğe ihtiyacı olmasa bile ata sınıfla birlikte gelen değişikliklere uyum sağlayacak şekilde değiştirilmelidir.

Devamını Oku…

Effective Java Madde 15: Değişebilirliği (Mutability) Kısıtlayın

Aralık 27th, 2016 No comments

Basit olarak tanımlamak gerekirse değişmez (immutable) sınıflar, nesneleri üzerinde değişiklik yapılamayan sınıflardır. Her bir nesne içinde tanımlı olan değerler, nesne yaratılırken belirlenir ve nesnenin ömrü boyunca aynı kalır. Java platformu içerisinde tanımlı String, Integer, Boolean, BigInteger, BigDecimal gibi birçok değişmez sınıf bulunmaktadır. Bunun sebebi değişmez sınıfların daha kolay tasarlanabilmesi, yazılabilmesi ve kullanılabilmesidir. Ayrıca, değişmez sınıflar hata yapmaya daha az olanak verir ve daha güvenlidirler.

Bir sınıfı değişmez yapmak için aşağıdaki 5 kuralı uygulamalısınız:

1. Nesnenin durumunu değiştiren hiçbir metot tanımlamayın.
2. Sınıfı kalıtılamaz hale getirin. Böylece yazdığınız sınıfın değişmezliği, kötü niyetli veya dikkatsizce yazılmış çocuk sınıflar tarafından etkilenmemiş olur. Bunu yapmak için genellikle sınıf tanımlanırken final anahtar kelimesi kullanılır, ancak başka bir yol daha var ve buna ilerde değineceğiz.
3. Sınıftaki bütün alanları (field) final olarak tanımlayın. Böylece alanlara ilk değerlerini atadıktan sonra değiştirilmesi mümkün olmayacaktır.
4. Sınıftaki bütün alanları private olarak tanımlayın. Böylece sınıf içerisinde değişebilir nesnelere referanslar varsa, bu nesnelerin değiştirilmesini engellemiş olursunuz. Her ne kadar değişmez sınıflar içerisinde temel değerler taşıyan (başka nesnelere referans olmayan) public final alanlar tanımlamak mümkün olsa da, ileride sınıfın iç yapısının değiştirilmesini kısıtlayacağı için önerilmez. (Madde 13)
5. Değişebilir alanlara olan erişimi kısıtlayın. Eğer değişmez sınıf içerisinde değişebilir nesnelere referanslar varsa, istemcilerinizin bu referanslara erişemediğinden emin olun. Bu tür referansları istemciye döndürmeniz gerekiyorsa, gösterdiği nesnenin bir kopyasını oluşturup onu döndürün. Aynı şekilde, örneğin bir yapıcı metot aracılığıyla istemciden gelen bir referansı değişmez sınıf içerisinde kullanmanız gerekiyorsa, yine nesnenin bir kopyasını oluşturup onu kullanın. Böylece istemci nesnede değişiklik yapsa bile değişmez sınıftaki nesneyi değil kopyasını değiştirmiş olacaktır. (Madde 39, Madde 76)

Devamını Oku…

Effective Java Madde 14: public sınıflarda erişim metotları kullanın, public alanlar değil

Aralık 24th, 2016 No comments

Zaman zaman birkaç tane alanı bir arada tutmaktan başka bir iş yapmayan sınıflar yazma eğiliminde olabilirsiniz:

// Bunun gibi sınıflar public olmamalıdır!
class Point {
    public double x;
    public double y;
}

Bu tür sınıfların veri alanları direk erişime açık olduğu için, kapsülleme prensibinin (encapsulation) faydalarını kullanamazlar. UPA’yı (API) değiştirmeden kod içerisinde değişiklik yapmak zorlaşır, sabit değerler tanımlayamazsınız ve bir alana erişildiğinde müdahale etme şansınız olmaz. Katı görüşlü programcılar bu tür sınıfları lanetli olarak görürler ve bunların yerine private alanları ve public erişim metotları olan sınıflar yazılması gerektiğini savunurlar.

Devamını Oku…

Effective Java Madde 13: Sınıfların ve Üyelerinin Erişilebilirliğini Kısıtlayın

Ağustos 12th, 2016 No comments

İyi tasarlanmış bir yazılım modülünü kötü tasarlanmış bir modülden ayıran en önemli faktör, içindeki verileri ve gerçekleştirim (implementation) detaylarını diğer modüllerden ne kadar iyi saklayabildiğidir. İyi tasarlanmış bir modül, gerçekleştirim detaylarını net bir biçimde diğer modüllerden gizler. Modüller birbirleriyle tanımladıkları API (Uygulama Programlama Arabirimi, UPA) üzerinden konuşurlar ve birbirlerinin iç dünyasından habersiz olmaları gerekir. Bu konsept, çok temel bir yazılım tasarım ilkesidir ve bilgi saklama yada kapsülleme (encapsulation) olarak bilinir.

Bilgi saklama konsepti birçok açıdan önemlidir. En önemli faydası ise yazılım modüllerini birbirinden ayrıştırarak (decoupling) birbirinden bağımsız bir şekilde geliştirilebilmesini, test edilebilmesini ve kullanılabilmesini sağlamaktır. Bu durum, bir sistemin geliştirilmesini hızlandırır çünkü farklı modüller paralel bir biçimde aynı anda geliştirilebilir. Ayrıca bakım yapmayı ve modülün anlaşılmasını kolaylaştırır, bir problem olduğunda diğer modülleri bozma riski olmadan hata araştırılıp, çeşitli çözümler denenebilir. Bilgi saklama kendi başına bir sistemin yüksek performansla çalışmasını sağlamasa da, birbirinden bağımsız modüllerin diğerlerini etkilemeden optimize edilebilmesini sağlar. Dolayısıyla sistemi test ederek hangi modülün yavaş çalıştığını tespit edebilir, sistemin diğer parçalarına zarar vermeden yavaş çalışan modülü optimize edebilirsiniz. Birbirinden bağımsız modüller aynı zamanda tekrar kullanılabilirliği (reusability) yüksek olan modüllerdir. Bilgi saklama tekniği büyük sistemler geliştirmenin riskini önemli ölçüde azaltır, çünkü sistem bir bütün olarak doğru çalışmasa da bağımsız modüllerin doğru çalıştığı kanıtlanabilir.

Devamını Oku…

Effective Java Madde 12: Comparable Arayüzünü Gerektiğinde Uygulayın

Temmuz 31st, 2016 No comments

Bu bölümde gördüğümüz diğer metotların aksine, compareTo() metodu Object içerisinde tanımlanmış değildir. Bunun yerine Comparable arayüzünün tek metodu olarak karşımıza çıkmaktadır. Karakter olarak Object sınıfındaki equals() metoduna benzer ancak eşitlik karşılaştırması yanında sıralama da yapabilir ve üreyseldir (generic). Comparable arayüzünü uygulayarak, sınıfınızın nesneleri arasında sıralama yapılabileceğini belirtmiş olursunuz. Bu arayüzü uygulayan nesnelerden oluşan bir diziyi (array) sıralamak aşağıdaki gibi son derece kolaydır:

Arrays.sort(a);

Benzer şekilde, Comparable arayüzü uygulandığında arama yapma, uç değerleri bulma, kendiliğinden sıralı veri yapılarını yönetme gibi problemler de çok kolaylaşır. Örneğin, aşağıdaki program komut satırından girilen parametreleri alfabetik sırada yazdırmakta ve tekrar edilen değerleri elemektedir. Bu kodun doğru çalışması String sınıfının Comparable arayüzünü uygulamasıyla mümkün olmaktadır.

public class WordList {
        public static void main(String[] args) {
        Set<String> s = new TreeSet<String>();
        Collections.addAll(s, args);
        System.out.println(s);
    }
}

Devamını Oku…

Effective Java Madde 10: toString() Metodunu Her Zaman Geçersiz Kılın

Mayıs 28th, 2016 No comments

Her ne kadar java.lang.Object bir toString() gerçekleştirimi sunsa da, geri döndürdüğü karakter dizisi genellikle sizin sınıfınızı kullanmak isteyen bir yazılımcının görmek istediği şey değildir. Bu değer sınıfın adı, ardından gelen ‘@’ karakteri ve nesnenin hash kodunun onaltılık sistemde (hexadecimal) ifadesini içermektedir, örneğin “PhoneNumber@163b91”. toString sözleşmesi, bu metottan döndürülen değerin “kolay okunup anlaşılabilen, kısa ama bilgi verici” olması gerektiğini söyler. “PhoneNumber@163b91” değerinin kısa ve okuması kolay olduğunu savunabilirsiniz ancak “(707) 867-5309” ile karşılaştırıldığında bilgi verici olmadığı açıktır. toString sözleşmesi bunların haricinde “Bu metodu bütün alt sınıfların geçersiz kılması tavsiye edilir” demektedir. Kesinlikle uyulması gereken bir tavsiye!

Her ne kadar equals (Madde 8) ve hashCode (Madde 9) sözleşmeleri kadar kritik olmasa da, güzel bir toString gerçekleştirimi sağlamak sınıfınızı çok daha kolay kullanılabilir hale getirir. toString metodu, bir nesne printf, println gibi metotlara parametre olarak geçildiğinde, karakter dizilerine eklendiğinde veya assert ile birlikte kullanıldığında otomatik olarak işletilir.

Devamını Oku…

Effective Java Madde 9: equals() ile Birlikte Mutlaka hashCode() Metodunu da Geçersiz Kılın

Mayıs 26th, 2016 2 comments

Önemli Not: Hash tabanlı veri yapılarının Java’da nasıl çalıştığını bilmiyorsanız bu yazıyı okumadan önce araştırmanızı şiddetle tavsiye ederim.

Object sınıfından gelen hashCode metodunu gerektiği yerde geçersiz kılmamak (override) birçok hatanın kaynağını oluşturur. equals metodunu geçersiz kıldığınız her sınıfta hashCode metodunu da geçersiz kılmanız gerekir. Bunu yapmamak Object.hashCode metodunun sözleşmesini ihlal etmek demektir, bu da sınıfınızın hash tabanlı HashMap, HashSet, HashTable gibi veri yapılarıyla birlikte kullandığında yanlış çalışmasına yol açar. Bunun sebebi ise Object sınıfından gelen hashCode metodunun hash kodunu hesaplarken nesnenin o anda bulunduğu bellek adresini kullanmasıdır. Her nesnenin bellek adresi farklı olacağı için hesaplanan hash kodu da farklı olacaktır. Object sınıfı belirtiminde tarif edildiği üzere sözleşme genel olarak şu şekildedir:

  • equals karşılaştırmasında kullanılan alanlar sabit kaldığı sürece, hashCode metodu aynı uygulama içerisinde üst üste çağrıldığında her zaman aynı sonucu üretmelidir.
  • Eğer iki nesne equals metoduna göre birbirine eşitse, bu iki nesnenin hashCode metotları da aynı integer değerini üretmelidir.
  • Eğer iki nesne equals metoduna göre eşit değilse, hashCode metodu bu iki nesne için farklı integer sonuçları üretmek zorunda değildir. Ancak yazılımcı bilmelidir ki eşit olmayan nesneler için farklı hash kodları üretmek hash table performansını artırabilir.

Devamını Oku…

Java’da Enum Türleri

Temmuz 23rd, 2015 1 comment

Merhabalar, Java dilinde Enum türlerini detaylarıyla anlatan Türkçe bir kaynak bulamadığım için bu yazıyı yazmaya karar verdim, umarım bu alandaki eksiği bir nebze olsun kapatır.

Java’da Enum türleri önceden tanımlanmış sabit değerleri ifade etmek için kullanılır. Peki bununla neyi kastediyoruz? Mesela en klasik örnek haftanın günleri. Bir haftanın kaç gün olduğu ve hangi günlerden oluştuğu bilindiğine göre bunu aşağıdaki gibi bir Enum türüyle ifade edebiliriz.

public enum Gun {
    PAZARTESI,
    SALI,
    CARSAMBA,
    PERSEMBE,
    CUMA,
    CUMARTESI,
    PAZAR
}

Devamını Oku…

Effective Java Madde 8: equals() Metodunu Geçersiz Kılarken Sözleşmeye Uyun

Şubat 9th, 2015 No comments

Java dilinde bütün sınıfların atası olan Object içerisinde, eşitlik kontrolü amacıyla kullanılan equals() metodunu geçersiz kılmak (override) çok zor bir iş gibi görünmese de bunu yanlış yapmak aslında çok daha kolay. Yanlış şekilde geçersiz kılınmış bir equals() metodu uygulamada ciddi sorunlar çıkmasına yol açabilir. Bu tarz problemlerden kaçınmanın en kolay yolu bu metodu geçersiz kılmamaktır. Bu durumda her nesne sadece kendisine eşit olacaktır. Object içerisindeki equals() metodu çok basit bir şekilde aşağıdaki gibi tanımlanmıştır:

public boolean equals(Object obj) {
    return (this == obj);
}

Gördüğünüz gibi Object sınıfında tanımlanan equals() metoduna göre her nesne sadece kendisine eşittir. Aşağıdaki durumlardan birisi söz konusuysa bu metoda dokunmamak en doğrusudur:
Devamını Oku…

Categories: Java Tags: ,

Effective Java Madde 7: Finalizer (Sonlandırıcı) Kullanmaktan Kaçının

Ocak 27th, 2015 2 comments

Java’da sonlandırıcılar (finalizer) çoğu durumda gereksiz, tehlikeli ve tutarsız davranışlar sergileyen metotlardır. Kullandığınız taktirde anlam veremediğiniz hatalı davranışlar, kötü performans ve taşınabilirlik (portability) sorunlarıyla karşılaşabilirsiniz. Sonlandırıcı kullanmak sadece bir iki durumda işe yarayabilir, onları da yazıda göreceğiz. Ancak genel bir kural olarak sonlandırıcı kullanmaktan sakınmalıyız.

Öncelikle sonlandırıcı derken tam olarak neyi kastettiğimizi söyleyelim. Java’da bütün sınıfların atası olan Object içerisinde aslında hiçbir iş yapmayan finalize() metodu vardır. Eğer yazılımcı nesne bellekten temizlenmeden önce bir takım kaynakları serbest bırakmak istiyorsa, bu metodu override edebilir. Teorik olarak çöp toplayıcı, bir nesne tamamen erişilemez duruma geldiğinde bu metodu çağıracak ve sistemden silinmeden önce finalize() metodunun içeriği işletilecektir. Ancak pratikte bu yaklaşım çalışmamakta ve uygulamada ciddi sorunlara yol açmaktadır.

Devamını Oku…

%d blogcu bunu beğendi: