Java'da Hata Ayıklama ve Yönetimi

Çalışma zamanında meydana gelene hataların bir bölümü Java'nın çalışmasını durdurmazken büyük bir bölümü ise Java'nın dolayısı ile de programın çalışmasını durduracaktır. Bir programcı ya da bir geliştirici olarak bu hataları yakalamak; mümkünse tamamen gidermek ya da çalışmayı durdurmayacak şekilde devam edebilmesini sağlamak gerekir.

Java'da hata yakalama 5 ifade ile yönetilir. Bunlar try, catch, throw, throws ve finally'dir.

Hata izlemesi yapmak istenilen kodlar try bloğuna yazılır.

Try bloğu içerisine yazılmış kodlarda bir hata oluşursa, bu hata fırlatılır. Java tarafında oluşan hatalar, Java tarafından otomatik olarak fırlatılır. Ancak bazı durumlarda hata fırlatma işlemini manuel olarak yapmanız gerekir. Bu durumda throw ifadesi ile hata fırlatma işlemi yapılır. Bazı durumlarda da yazdığınız metodun hangi hataları fırlatabileceğini metod imzasında belirtmeniz gerekir. Bu durumda da throws ifadesi kullanır.

Fırlatılan hata catch bloğu ya da blokları tarafından yakalanır ve işlenir.

Hata olsun ya da olmasın yapılması gereken bir işlem varsa o da finally bloğunda yaptırılır.

Genel yapısı şu şekildedir;

try{
//Hata oluşması muhtemelen kodlar bloğu.
}catch(ExceptionType1 e){
//ExceptionType1 için işleyici blok
}catch(ExceptionType2 e){
//ExceptionType2 için işleyici blok.
}finally{
//Hata olsun yada olması bu blok çalışır.
}

try

Bu kod bloğu içerisine izlemek ya da hataları yakalamak istediğiniz kodlar yazılır. Bu kod bloğu içerisinde bir hata fırlatılana kadar kodlar çalıştırılır. Bu blok içerisinde bir hata fırlatıldıktan sonra yer alan kodlar çalıştırılmaz.

catch

Try bloğu içerisinde bir hata fırlatılmış ise en uygun catch bloğu içerisindeki kodlar çalıştırılır.

Bir hata fırlatılmamış ise hiçbir catch bloğu çalıştırılmaz.

catch ifadesinden sonra parantez içerisinde parantez içerisinde hatayı bildiren sınıf ve bir boşluk sonra bu sınıf ile oluşturulacak nesne tanımlanmış oluyor. Hatayı bildiren sınıflar Java tarafından önceden belirlenmiştir.
Örneğin matematiksel hatalarda ArithmeticException sınıfı kullanılır.
Her hata türü için özelleştirme yapmak zorunda değilsiniz. Java'nın genel hata yönetim sınıfı Exception kullanabilirsiniz.

finally

Bir hata fırlatılmış olsun ya da olmasın çalıştırılması gereken kodları ifade eder. Bu kod bloğunun olması zorunlu değildir.

x(), y(), z() isimli üç metodumuz olduğunu düşünelim. x() metodu içerisinde y() metodunu ve y() metodu da z() metodunu çağırıyor olsun. z() içerisinde bir hata oluştuğunda z() metodu içerisinde hata yakalama işlemi yapılmıyor ise; bu hata y() metoduna gönderilir. y() metodu içerisinde de hata yakalama işlemi yapılmıyorsa bu hata x() metoduna gönderilir. x() metodunda da hata yakalanmıyorsa; main metoda ulaşana kadar hiyerarşik olarak hata gönderilmeye devam eder.

Basit bir örnekle Java'da hata ayıklama;

public class Main {
public static void main(String[] args) {

int sonuc = 0, bolen, bolunen;

bolunen = 5;
bolen = 0;

System.out.println("Program başladı.");

try {
System.out.println("Hesaplanıyor...");
sonuc = bolunen / bolen;
System.out.println("Sonuç : " + sonuc);
}catch(ArithmeticException e) {
System.out.println("Hata : " + e.getMessage());
}

System.out.println("Program Sonlandı!");

}
}

Yukarıda basit bir sıfıra bölünme hatası görüyorsunuz. Bu kodun çıktısı şöyledir;

Program başladı.
Hesaplanıyor...
Hata : / by zero
Program Sonlandı!

Birden fazla catch bloğu kullanımana örnek olarak;

public class Main {
public static void main(String[] args) {

int sonuc = 0, bolen, bolunen;
bolunen = 5;
bolen = 2;

int[] arr = new int[3];

System.out.println("Program başladı.");

try {
System.out.println("Hesaplanıyor...");
sonuc = bolunen / bolen;
System.out.println(bolunen + "/" + bolen + "=" + sonuc);

arr[4] = 10;
System.out.println("arr dizisi güncellendi.");
}catch(ArithmeticException e) {
System.out.println("MAtematik Hatası : " + e.getMessage());
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Dizi Hatası : " + e.getMessage());
}

System.out.println("Program Sonlandı!");

}
}

Yukarıdaki örneği çıktısı;

Program başladı.
Hesaplanıyor...
5/2=2
Dizi Hatası : Index 4 out of bounds for length 3
Program Sonlandı!

Hata Fırlatma

Java'da hata fırlatma işlemini manuel olarak yapmakta mümkündür. Bir hata fırlatmak istediğimizde throw ifadesini kullanırız.

Örneğin;

public class Main {
public static void main(String[] args) {

int sonuc = 0, bolen, bolunen;
bolunen = 5;
bolen = 1;

System.out.println("Program başladı.");

try {
System.out.println("Hesaplanıyor...");
if(bolen == 1) {
throw new ArithmeticException("Bir değerin 1'e bölümü kendisine eşittir.");
}
sonuc = bolunen / bolen;
System.out.println(bolunen + "/" + bolen + "=" + sonuc);
}catch(ArithmeticException e) {
System.out.println("Matematik Hatası : " + e.getMessage());
}

System.out.println("Program Sonlandı!");

}
}

Yukarıdaki örneğin çıktısı şöyledir;

Program başladı.
Hesaplanıyor...
Matematik Hatası : Bir değerin 1'e bölümü kendisine eşittir.
Program Sonlandı!

Gördüğünüz gibi normal şartlarda bir sorun olmayan bir işlem için hata oluşturup fırlattık ve hatayı yakaladık.

Not : Fırlatma işlemi (throw) farklı bir metot içerisinde de yapılabilir. Ancak hatayı yakalamak istiyorsanız bu metodu try bloğu içerisinde çağırmanız gerektiğini unutmayın.

public class Main {

public static void bol(int bolunen, int bolen) {
if(bolen == 0) {
throw new ArithmeticException("Sıfır'a bölünemez.");
} else if(bolen == 1) {
throw new ArithmeticException("Bir değerin 1'e bölümü kendisine eşittir.");
}
int sonuc = bolunen / bolen;
System.out.println(bolunen + "/" + bolen + "=" + sonuc);
}

public static void main(String[] args) {
System.out.println("Program başladı.");

try {
bol(6, 3);
bol(4, 0);
bol(5, 1);
}catch(ArithmeticException e) {
System.out.println("Matematik Hatası : " + e.getMessage());
}

System.out.println("Program Sonlandı!");

}
}

Yukarıdaki örneğin çıktısı;

Program başladı.
6/3=2
Matematik Hatası : Sıfır'a bölünemez.
Program Sonlandı!

gördüğünüz gibi 6'yı 3'e böldü ve yazdı. Ancak 4'ü 0'a bölerken hata fırlattığı için sonraki 5'i 1'e bölme işlemini çalıştırmadan hatayı ekrana bastı.

Fark ettiyseniz yukarıdaki örneklerde hep try bloğu içerisinde throw ifadesini kullanarak hata fırlatma işlemini gerçekleştirdim. Bu çoğu zaman bu şekilde gerçekleşmez. try bloğunu sadece fırlatılmış bir hata ya da istisnayı yakalamak için kullanmak gerekir. Eğer bir metod içerisinde bir hata fırlatmanız gerekirse; metodu tanımlarken bu metodun hangi hataları fırlatabileceğini de bildirmeniz gerekir. Bunu throws ifadesi ile belirtebilirsiniz.

public class Student {

public Student search(int id) throws Exception {
if(id == 321){
return new Student();
}else{
throw new Exception('Öğrenci bulunamadı.');
}
}

}

Fark edebileceğiniz gibi bu şekilde bir yazım daha temiz ve daha okunaklı görünüyor.

Java'da Kendi Hata Sınıfınızı Yazmak

Programlar yazarken hataları özelleştirmek geliştirme sürecinde katkı sağlayabiliyor. Fırlatılabilir bir hata sınıfı yazmak sıradan bir sınıf yazmaktan farksızdır. Sadece Java'nın dahili bir hata sınıfını kalıtım olarak alması yeterlidir.

public class MyCustomException extends Exception {
public MyCustomException(String msg){
super(msg);
}
}

Yukarıdaki kodu incelediğimizde MyCustomException adında bir sınıf oluşturduğumu ve Java'nın Exception sınıfını miras aldığımı görebilirsiniz. Sonrasında bir kurucu (construct) metod ile girilecek hata iletisini üst sınıfına bildiriyorum.

Bu sınıf üzerinden bir hata fırlatmak istersem;

throw new MyCustomException('Bir hata oluştu');

şeklinde kullanabilirim.

Java programlama dilinde hata ayıklama ve hata yönetim süreci temel hatları ile bu şekilde yapılıyor.