Neler yeni
Türkiye'nin En Güncel Forum Sitesi

Forum içeriğine ve tüm hizmetlerimize erişim sağlamak için foruma kayıt olmalı yada giriş yapmalısınız. Forum üye olmak tamamen ücretsizdir.

Javada uygulamarımızı geliştirirken çoğu zaman hata yakalama mekanizmasıyla çalışmamı

ByOnur58

Kayıtlı Üye
MFC Üyesi
  • Üyelik Tarihi
    7 Ocak 2015
  • Mesajlar
    2,113
  • MFC Puanı
    10
  • MFC Seviyesi

Javada uygulamarımızı geliştirirken çoğu zaman hata yakalama mekanizmasıyla çalışmamız gerekiyor. Hata yakalama mekanizması nesneye yönelik programlamanın yapı taşlarındandır. Tabiki de bunu en dogru ve kullanışlı uygulamak kodunuzun geliceği için çok önemli.
Javada uygulamarımızı geliştirirken çoğu zaman hata yakalama mekanizmasıyla çalışmamız gerekiyor. Hata yakalama mekanizması nesneye yönelik programlamanın yapı taşlarındandır. Tabiki de bunu en dogru ve kullanışlı uygulamak kodunuzun geliceği için çok önemli. Şimdi hata yakalamanın neden bu kadar önemli olduguna bir göz atalım.

Şimdi makalemizin içinde kullanıcağımız bir kac yardımcı sınıf oluşturalım. Örneğimizde bir dosya yönetim sınıfı olacak ve bu sınıf içinde verilen bir dosyayı bulmak ve silmek gibi özellikler olacak.

Temel hata yakalama



public class DosyaYonetimi {

public Dosya dosyaBul(int dosyaNo) throws Exception {
throw new Exception("Dosya bulunamadi");
}

public **** dosyaSil(int dosyaNo) throws Exception{
throw new Exception("Dosya silinemez, baska biri tarafindan kullaniliyor");
}
}


Yardımcı sınıf

public class Dosya {

private int dosyaNo;

public **** setDosyaNo(int dosyaNo) {
this.dosyaNo = dosyaNo;
}
public int getDosyaNo() {
return this.dosyaNo;
}
}


Şimdide bu sınıfı test edelim:

public static **** main(String args[]) {
DosyaYonetimi yonetim = new DosyaYonetimi();

try {
Dosya d = yonetim.dosyaBul(1);
yonetim.dosyaSil(d.getDosyaNo());
} catch(Exception ex) {
System.err.println(ex.getMessage());
}
}


Yukarıdaki main içinde DosyaYonetimi sınıfı test ediliyor. Önce bir dosya bulunuyor ve sonra sorun çıkmazsa o dosya siliniyor. DosyaYonetimi sınıfı içindeki dosyaBul ve dosyaSil methodları Exception sınıfı hatasını atıyorlar. Test ederken her hangi bir hata olustuğunda catch bölümü içinde bu hata ekrana yazılıyor.

Ayrı hata sınıfları oluşturmak

Şimdiye kadar temel hata yakalama mekanızmasını gördük. Hata yakalama mekanizmasını bu şekilde kullanmak hiç bir zaman tavsiye edilmez. Bunun nedenlerinden en önemlisi kodun okunulur halden çıkması ve programınızın enden ve boydan genişledikçe karmakarışık bir hal almasıdır. Çünkü program genişledikçe her hata oluştuğu zaman farklı şeyler yapmanız gerekebilir ve bu halde hangi hata hangisinin artık bulunamaz hale gelir.

Bunu önlemek için her oluşabilecek hata için yeni bir hata sınıfı yapmanız olacak. Şimdi gelin yazdığımız kodu yeni hata sınıflarıyla değiştirelim.

Aranan dosya bulunamadığı zaman dosya bulunamadı adında bir hata yapalım.


public class DosyaBulunamadiException extends Exception {

public DosyaBulunamadiException(String mesaj) {
super(mesaj);
}
}


Ve şimdide dosya silinemez adında bir hata sınıfı yapalım.


public class DosyaSilinemezException extends Exception {

public DosyaSilinemezException(String mesaj) {
super(mesaj);
}
}


Ve şimdide DosyaYonetimi sınıfını ve test sınıfımızı değiştirelim.


public class DosyaYonetimi {

public Dosya dosyaBul(int dosyaNo) throws DosyaBulunamadiException {
throw new DosyaBulunamadiException("Dosya bulunamadi");
}

public **** dosyaSil(int dosyaNo) throws DosyaSilinemezException {
throw new DosyaSilinemezException("Dosya silinemez, baska biri tarafindan kullaniliyor");
}
}



public static **** main(String args[]) {
DosyaYonetimi yonetim = new DosyaYonetimi();

try {
Dosya d = yonetim.dosyaBul(1);
yonetim.dosyaSil(d.getDosyaNo());

} catch(DosyaBulunamadiException ex) {
System.err.println(ex.getMessage());
} catch(DosyaSilinemezException ex) {
System.err.println(ex.getMessage());
} catch(Exception ex) {
System.err.println(“Belirsiz bir hata oluştu: ” + ex.getMessage());
}
}


Her hata için ayrı bir hata sınıfı yapmakla kodumuzu daha okunaklı bir hale getiriyoruz ve de hangi hata için ne yapmamız hakkında da daha kullanılır oluyor.

Hata mesajlarını zenginleştirmek

Sanırım buraya kadar çoğu Java programcısı için yeni bir şey teşkil etmiyor. İsterseniz hata mesajlarını biraz daha güzelleştirelim. Mesela şu an hangi dosya no olduğunu biliyoruzç Fakat programımız içinde bunu bilemiyeceğiz. Bu nedenle de hata mesajımızı dosya numarası bigisiyle zenginleştirelim.


public class DosyaYonetimi {

public Dosya dosyaBul(int dosyaNo) throws DosyaBulunamadiException {
throw new DosyaBulunamadiException ("Dosya no " + dosyaNo + " bulunamadi");
}

public **** dosyaSil(int dosyaNo) throws DosyaSilinemezException {
throw new DosyaSilinemezException ("Dosya no " + dosyaNo + " silinemez, "+ kullananKisi + "tarafindan kullaniliyor");
}
}

*KullananKisi nesnesi o anda o dosyayı kullanan kişi yerine geçiyor.

Bakın şu an kodumuz çok daha profesyonelce oldu ve de hangi dosya numarası oldugunu ve de kim tarafından kullanıldığını biliyoruz.

Ana hata sınıfları oluşturmak

Diyelim programımız içinde dosyalarla alakalı 6 tane hata sınıfımız var. Her seferinde try ... catch yaparken bütün hata sınıflarını yazmak sanırım iyi olmaz. Bunu önlemek için dosyalar sınıfları için bir ana hata sınıfı yapmamız gerekecek ve tüm dosya sınıflarıda bu hata sınıfını kullanıcak.


public class DosyaException extends Exception {

public DosyaException(String mesaj) {
super(mesaj);
}
}

public class DosyaBulunamadiException extends DosyaException {

public DosyaBulunamadiException(String mesaj) {
super(mesaj);
}
}

public class DosyaSilinemezException extends DosyaException {

public DosyaSilinemezException(String mesaj) {
super(mesaj);
}
}



Böylelikle tüm dosya hatalarını bir kere de yakalayabiliyoruz.


public static **** main(String args[]) {
DosyaYonetimi yonetim = new DosyaYonetimi();

try {
Dosya d = yonetim.dosyaBul(1);
yonetim.dosyaSil(d.getDosyaNo());
} catch(DosyaException ex) {
System.err.println(ex.getMessage());
} catch(Exception ex) {
System.err.println(“Belirsiz bir hata oluştu: ” + ex.getMessage());
}
}


Internalization, Loglama ve advanced hata yakalama

Şu ana kadar orta derecedeki bir java programcısının hata yakalama mekanızmasını nasıl kullandığını gördük. Şimdi ise bu mekanızmayı nasıl international ve daha üst düzeyde kullanabileceğimizi görüceğiz.

Logging
Önce log yazma olayına girelim. Her programcı yazdığı kodda bir hata oluştuğu zaman bunu log”a yazar. Bunun içinde genelde Log4J kullanılır. (Log4J nasıl kullanılır konusunu girmeyeceğim)

Bu loga yazma olayını çoğu kişi try .. catch yaptığı yerde yazar. Yani bir hata oluştuğu anda o hatanın mesajını catch içerisinde loga yazar. Aşağıdakı örnekte olduğuu gibiŞ


public static **** main(String args[]) {
DosyaYonetimi yonetim = new DosyaYonetimi();

Log logger = LogFactory.getLog(Test.class);
try {
Dosya d = yonetim.dosyaBul(1);
yonetim.dosyaSil(1);
} catch(DosyaException ex) {
logger.error(ex.getMessage());
} catch(Exception ex) {
logger.error("Bilinmeyen bir hata olustu: " + ex.getMessage());
}
}


Bu log olayının yerine System.out.println da yazılabilir. Yani log4J bilmeyen kişiler bu logger.error kodunu System.out.println olarak görsün.

Bu loglama olayını hata sınıfının içinde yapmak her zaman çok iyidir ve try ... catch cok daha okunaklı hale gelir. Bunu şoyle yapabiliriz.


public class DosyaException extends Exception {

public DosyaException(String mesaj) {
super(mesaj);
Log logger = LogFactory.getLog(DosyaException.class);
logger.error(mesaj);
}
}


Böylelikle loglama olayı sadece bir yerde oluyor ve böylelikle acaba hataları loga yazıyormuyum diye düşünmeye gerek yok. Her hata atıldığında hatanın içeriği loga yazılır. Yalnız bunun bir dezavantajı log4J kullanan kişi hatalara baktığı zaman sınıf ismi olarak hep DosyaException görür ve acaba hangi hata sınıfından atıldığını bilemez. Eğer bu sorun olucaksa hataları loga yazma olayını her hata sınıfında yaparsınız. Yani şöyle:


public class DosyaException extends Exception {

public DosyaException(String mesaj) {
super(mesaj);
}
}

public class DosyaBulunamadiException extends DosyaException {

public DosyaBulunamadiException(String mesaj) {
super(mesaj);
Log logger = LogFactory.getLog(DosyaBulunamadiException.class);
logger.error(mesaj);
}
}

public class DosyaSilinemezException extends DosyaException {

public DosyaSilinemezException(String mesaj) {
super(mesaj);
Log logger = LogFactory.getLog(DosyaSilinemezException.class);
logger.error(mesaj);
}
}


Advanced Hata Yakalama

Yaptıgımız hata sınıflarını bir method içinde atarken her zaman bir mesaj yazıyoruz. Mesela yukarıdaki örneklerde olduğu gibi:


throw new DosyaBulunamadiException ("Dosya no " + dosyaNo + "bulunamadi");

Burda DosyaBulunamadiException sınıfı için önemli olan hangi dosya numarasıdır. Bunun dışında bizim gönderdiğimiz diğer mesaj onun için fazla önemli değil. Bu yüzden de bu hata sınıfını sadece dosyano bekliycek şekilde değiştirelim.


public class DosyaBulunamadiException extends DosyaException {

public DosyaBulunamadiException(int dosyaNo) {
super("Dosya no " + dosyaNo + "bulunamadi");
Log logger = LogFactory.getLog(DosyaBulunamadiException.class);
logger.error("Dosya no " + dosyaNo + "bulunamadi");
}
}


Böylelikle biz hatayı atarken hangi bilgi önemli ise onu veriyoruz ve oluşturulacak mesaj hakkında düşünmemize gerek kalmıyor. Şimdi bu hatayı nasıl attığımıza bakalım:


public class DosyaYonetimi {

public Dosya dosyaBul(int dosyaNo) throws DosyaBulunamadiException {
throw new DosyaBulunamadiException (dosyaNo);
}

public **** dosyaSil(int dosyaNo) throws DosyaSilinemezException {
throw new DosyaSilinemezException (dosyaNo, kullananKisi);
}
}


Internalization

Farzedin bu yazıcağınız program Türkiye yanında diğer yabancı ülkelerdede kullanılacak. Bu yüzdende oluşan hataları ekrana (kullanıcıya) gösterirken kullanıcının kendi dilinde göstermemiz gerekiyor. Şu anki haliyle bunu yapmak imkansız gibi birşey. Ya her ülke için ayrı bir program derliyceksiniz, yada her ülke için ayrı ayrı hata sınıfları yazıcaksınız.

Ama çok daha kolay bir yol daha var: Bundle lerle çalışmak. Yani mesajların içeriğini .properties dosyalardan almak.

Önce mesajları kaydediceğimiz bir dosya yapalım.


hatalar_tr.properties
error.dosya.bulunamadi=Dosya no {0} bulunamadı
error.dosya.silinemiyor=Dosya no {0} silinemiyor, {1} tarafindan kullanılıyor


Bu yaptığımız file (dosyayı) .class dosyalarının bulunduğu yere koyalım.

Bu yukarıda yazdığımız hata isimlerini java classlarımızada tanıtmamız lazım bunun için bir interface yapalım.


interface Hatalar {
public String DOSYA_BULUNAMADI = "error.dosya.bulunamadi";
public String DOSYA_SILINEMIYOR = "error.dosya.silinemiyor";
}


Şimdi de hata sınıflarını değiştirelim:


public class DosyaException extends Exception {

private String hataKodu;

private Object[] value;

public DosyaException (Object[] value, String hataKodu) {
super(ResourceBundleReader.getFormattedMessage(val ue, hataKodu));
this.hataKodu = hataKodu;
this.value = value;
Log logger = LogFactory.getLog(DosyaException.class);
logger.error(ResourceBundleReader.getFormattedMess age(value, hataKodu));
}

public String getHataKodu() {
return hataKodu;
}
public Object[] getValue() {
return value;
}
}

public class DosyaBulunamadiException extends DosyaException {

public DosyaBulunamadiException(int dosyaNo) {
super(new Object[]{new Integer(dosyaNo)}, Hatalar.DOSYA_BULUNAMADI);

}
}

public class DosyaSilinemezException extends DosyaException {

public DosyaSilinemezException(int dosyaNo, String kullananKisi) {
super(new Object[]{new Integer(dosyaNo), kullananKisi}, Hatalar. DOSYA_SILINEMIYOR)
}
}


Hataları okumak için yardımcı bir sınıf yapalım.


public class ResourceBundleReader {

public static String getFormattedMessage(Object[] value, String hataKodu) {
String ret = null;
MessageFormat format = null;
String mesg = null;
ResourceBundle bundle = ResourceBundle.getBundle("hatalar");
try {
mesg = bundle.getString(hataKodu);
format = new MessageFormat(mesg);
ret = format.format(value);
} catch (Exception e) {
logger.error("Could not format message " + ex);
try {
ret = format.format(null);
} catch (Exception ex) {
ret = mesg;
}
}
return ret;
}

}



MessageFormat sınıfı Javanın kendine ait bir sınıftır.

Bu yaptığımız mekanizmayla bir hata oluştuğu anda hemen super(…) çağırıp hangi hataKodunu ve hangi bilgilerin olduğunu verirsin. DosyaException ise gelen hataKoduyla gidip hatalar.properties dosyasından mesajı alır ve mesaj içindeki boş yerleri senin verdiğin bilgi sırasına gore doldurur. Eğer bu program Türkiye”de çalışırsa gidip hatalar_tr.properties dosyasını arar. Mesela Ingiltere”de çalışırsa hatalar_en.properties dosyasını kullanır. Böylelikle programınızın tüm hata yakalama mekanizması internasyonal olur.

Mesela Ingiltere”de çalışıyor program.

Dosyamızda şöyle:


hatalar_en.properties
error.dosya.bulunamadi=File with number {0} is not found
error.dosya.silinemiyor= File with number {0} could not be deleted, it is in use by {1}


Bu durumda programda silinemiyor hatası oluşsa sonuç şöyle olur:


throw new DosyaBulunamadiException(10, “Ahmet”);
 
Üst Alt