SİTE
İÇİ ARAMA |
|
Blogroll |
|
|
|
Java - Exceptions ( İstisnalar ) |
|
Gönderiliyor lütfen bekleyin... |
|
|
Bu yazımızda
istisnalar üzerinde durulacaktır. İstisna deyince aklınıza ne geliyor? Yanlış
yazılmış uygulama mı? Beklenmeyen durum mu? Yoksa her ikisi de mi? İstisna
demek işlerin sizin kontrolünüzden çıkması anlamına gelir. Yani karışıklık
ortamı, önceden kestirilemeyen... Bir şeylerin ters gitmesi sonucu uygulamanın
normal akışına devam edememesi demektir. Bu ters giden bir şeyler ne olabilir?
Örneğin kullanıcının uygulamanıza istemeyen veri girmesi olabilir veya açmak
istediğiniz dosyanın yerinde olmaması olabilir, örnekleri çoğaltmak mümkündür.
İstisnalara Giriş
Gerçekten
tam bir uygulama yazmak ne demektir? Uygulamadan beklenen görevleri
yerine getirmesi onu tam bir uygulama yapar mı? Tabii ki yapmaz. Uygulama zaten
kendisinden beklenen işi yapmalı, aksi takdirde zaten uygulama olmaz. Bir
uygulamanın tam olmasının iki şartı vardır; Birincisi uygulamanın
kendisinden beklenen görevleri doğru bir şekilde yerine getirmesidir yani doğruluk,
ikincisi ise hatalı davranışlara karşı dayanıklı olmasıdır, sağlamlık.
Örneğin bizden iki sayıyı bölmek için bir uygulama istense ne yapılmalıdır, A/
B - A bölüm B çok basit değil mi?. İlk etapta karşı tarafın bizden istediği
şey, girilen iki sayının doğru şekilde bölünmesidir - doğruluk, bu öncelikli
şarttır, bunda herkes hemfikir. Peki ikinci şart nedir? İkinci şart ise
sağlamlıktır, ikinci şart olan sağlamlık genellikle önemsenmez. Bu örneğimizde
karşı tarafın bizden istediği olay, iki sayının bölünmesidir ama dikkat edin sayı
dedim, kullanıcı int, double veya short ilkel tiplerinde
sayı girilebilir. Peki ya kullanıcı String bir ifadeyi uygulamanıza
yollarsa ne olur? veya A=5, B=0 girince uygulamanız buna nasıl bir tepki verir?
(Not :5/0=sonsuz) Uygulamanız direk olarak kapanır mı? Veya uygulamanız bu
anlamsız ifadeleri bölmeye mi çalışır? Eğer siz uygulamayı tasarlayan kişi
olarak, bu hataları önceden tahmin etmiş ve önlemleri almışsanız sorun ortaya
çıksa bile, uygulama için sorun olmaz ama gerçek dünyada her şeyi öngörebilmek
imkansızdır.
Java
programlama dili, oluşabilecek hatalara karşı sert bir yaptırım uygular.
Dikkat edin, oluşabilecek diyorum. Java programlama dili, ortada hata
oluşmasına sebebiyet verebilecek bir durum var ise yazılan Java dosyasını
derlemeyerek kodu yazan kişiye gerekli sert tavrı gösterir.
Java programlama dilinin bu tavrı doğru mudur? Kimileriniz diyebilir ki,
"Java sadece üstüne düşen görevi yapsın, oluşabilecek hataları bana
söyleyerek canımı sıkmasın". Bu yaklaşım yanlıştır, Java programlama
dilinin amacı kodu yazan kişiye maksimum şekilde yardımcı olmaktır, daha
doğrusu insana dayalı oluşabilecek hataları kendi üstüne alıp, hatalı uygulama
üretimini minimuma indirgemeyi amaçlayarak tasarlanmıştır. Bunun ilk örneğini
çöp toplama (garbage collector) mekanizmasında görmüştük. Diğer dillerde
oluşturulan nesnelerin, daha sonradan işleri bitince bellekten silinmemelerinden
dolayı bellek yetmezlikleri oluşmaktadır. " Kodu yazan insan, oluşturduğu
nesneyi bellekten temizlemez mi? Ben bunu şahsen hiç yapmam. O zaman dalgın
insanlar kod yazmasın aaa! " diye bir söz sakın demeyin, çünkü
insanoğlu yeri geldiğinde çok dalgın olabilir ve bu dalgınlık uygulamayı bir
bellek canavarına dönüştürebilir ayrıca bu tür hataları, uygulamanın
içerisinden ayıklamak cidden çok zor bir iştir. Bu yüzden Java programlama
dilinde, bir nesnenin bellekten silinmesi kodu yazan kişiye göre değil, çöp
toplama algoritmalarına göre yapılır. Java’nın oluşabilecek
olan hatalara karşı bu sert tutumu da gayet mantıklıdır. Bu sert tutum
sayesinde ileride oluşabilecek ve bulunması çok güç olan hataların erkenden
engellenmesini sağlar.
İstisna Nasıl Oluşabilir?
İstisna
oluşumuna en basit örnek olarak, yanlış kullanılmış dizi uygulamasını
verebiliriz. Java programlama dilinde dizilere erişim her zaman kontrollüdür.
Bunun anlamı, Java programlama dilinde dizilerin içerisine bir eleman atmak
istiyorsak veya var olan bir elemana ulaşmak istiyorsak, bu işlemlerin hepsi
Java tarafından önce bir kontrolden geçirilir. Bunun bir avantajı, bir de
dezavantajı vardır. Avantaj olarak güvenli bir dizi erişim mekanizmasına sahip
oluruz, dezavantaj olarak ufakta olsa hız kaybı meydana gelir. Fakat böyle bir
durumda hız mı daha önemlidir yoksa güvenlik mi? Bu sorunun cevabı Java
programlama dili için güvenliktir. Aşağıdaki örneğe dikkat edelim;
package makaleKod;
public class DiziErisim
{public DiziErisim() { } public static void main(String[] args) {
{ int sayilar[]={1,2,3,4}; System.out.println("Basla");
for (int i
= 0; i < 5; i++) { System.out.println("--> " + sayilar[i]);
}
System.out.println("Bitti");
} } }
|
ayilar[],ilkel (primitive)
int tipinde dizi değişkenidir ve bağlı bulunduğu dizi nesnesinin içerisinde 4
adet int tipinde eleman vardır. for döngüsü sayesinde dizi içerisindeki
elemanları ekrana bastırmaktayız. Bu örneğimizdeki hata, for döngüsünün fazla
dönmesiyle dizinin olmayan elemanına ulaşmak istememizden kaynaklanmaktadır.
Böyle bir hareket, çalışma-anında (run-time) hata oluşmasına sebebiyet
verip uygulamamızın aniden sonlanmasına sebebiyet verecektir. Uygulamayı
çalıştırıp, sonuçları hep beraber görelim.
Bu
örneğimizdeki istisna, ArrayIndexOutOfBoundsException istisnasıdır. Bu
istisnanın sebebi, bir dizinin olmayan elemanına erişmeye çalıştığımızı ifade
eder. Fark edildiği üzere Java programlama dilinde, oluşan istisnaları anlamak
ve yerlerini belirlemek çok zor değildir. Örneğin bu uygulamada istisnanın
10. satırda ortaya çıktığı anlaşılabilmektedir.
Başka İstisnalar Neler Olabilir?
Bir uygulama içerisinde, başka ne tür istisnalar oluşabilir ? Bir kaç örnek verirsek;
• Açmak istediğiniz fiziksel dosya yerinde olmayabilir.
• Uygulamanıza kullanıcılar tarafında, beklenmedik bir girdi kümesi gelebilir.
• Ağ bağlantısı kopmuş olabilir.
• Yazmak istediğiniz dosya, başkası tarafından açılmış olduğundan yazma hakkınız olmayabilir.
Olabilir, olmayabilir, belki... Yukarıdaki istisnaların, bir uygulamanın başına
gelmeyeceğini kim garanti edebilir? Kimse, peki Java program içerisinde tam bir uygulama nasıl yazılır. Başlayalım...
İstisna Yakalama Mekanizması
Bir istisna oluştuğu zaman uygulamamız aniden kapanmak zorunda mı? Oluşan bu istisnayı daha şık bir şekilde
yakalayıp uygulamanın devam etmesini sağlamak mümkün mü? Cevap olarak evet;
try{// Istisnaya sebebiyet verebilecek olan kod } catch(Exception1
e1) { //Eger Exception1 tipinde istisna firlatilirsa buraya
} catch(Exception2 e2) { //Eger Exception2
tipinde istisna firlatilirsa buraya }
|
İstisnaya
sebebiyet verebilecek olan kod, try bloğunun içerisinde tutularak güvenlik
altına alınmış olur. Eğer istisna oluşursa, istisna yakalama mekanizması
devreye girer ve oluşan bu istisnanın tipine göre, uygulamanın akışı catch bloklarından
birinin içerisine yönlenerek devam eder.
İstisnalar nesnedir. Bir istisna oluştuğu zaman bir çok olay gerçekleşir. İlk önce
yeni bir istisna nesnesi belleğin heap alında new() anahtar kelimesi ile oluşturulur.
Oluşan bu istisna nesnesinin içerisine hatanın oluştuğu satır yerleştirilir.
Uygulamanın normal seyri durur ve oluşan bu istisnanın yakalanması için catch bloğunun olup
olmadığına bakılır. Eğer catch bloğu varsa uygulamanın akışı uygun catch bloğunun içerisinden devam eder. Eğer catch bloğu
tanımlanmamış ise hatanın oluştuğu yordamı (method)
çağıran yordama istisna nesnesi paslanır, eğer bu yordam içerisinde de istisnayı yakalamak için
catch bloğu tanımlanmamış ise istina nesnesi bir üst yordama paslanır, bu olay böyle devam eder ve en sonunda main() yordamına ulaşan istisna nesnesi için bir catch bloğu aranır eğer
bu yordamın içerisinde de catch bloğu tanımlanmamış ise, uygulananın akışı sonlanır. Bu olayları detaylı incelemeden
önce temel bir giriş yapalım;
package makaleKod;
public class DiziErisim2 {
private void calis() { int sayilar[]={1,2,3,4}; for (int i = 0; i
< 5; i++) { try { System.out.println("-->"+sayilar[i]); } catch (ArrayIndexOutOfBoundsException
ex) { System.out.println("Hata olustu" +ex); } } } public
static void main(String args[]) { System.out.println("Basla");
DiziErisim2 de2=new DiziErisim2(); de2.calis(); System.out.println("Bitti");
} }
|
Yukarıdaki uygulamamızda, dizi elemanlarına erişen kodu try bloğu içerisine alarak, oluşabilecek olan
istinaları yakalama şansına sahip olduk. Sahip olduk da ne oldu diyenler için
gereken açıklamayı hemen yapalım. try-catch istisna yakalama mekanizması
sayesinde istisna oluşsa bile uygulamanın akışı aniden sonlanmayacaktır.
DiziErisim.java
ile DiziErisim2.java uygulamalarının çıktısına bakılırsa aradaki
kontrolü hemen fark edilecektir. DiziErisim2.java uygulama örneğimizin
çıktısı aşağıdaki gibidir.
Kontrol
nerede? Yukarıdaki DiziErisim2.java uygulamasının çıktısının son
satırına dikkat ederseniz, "Bitti" yazısının ekrana yazıldığını
görürsünüz oysaki bu ifade DiziErisim.java uygulamasının çıktısında
görememiştik. İşte kontrol buradadır. Birinci kuralı daha net bir şekilde ifade
edersek; try-catch istisna yakalama
mekanizması sayesinde, istisna oluşsa bile uygulamanın akışı aniden sonlanmaz.
Yukarıdaki örneğimizde, try-catch mekanizmasını for döngüsünün içerisine koyulabileceği gibi, for döngüsünü kapsayacak şekilde de tasarlanıp
yerleştirilebilir.
package makaleKod;
public class DiziErisim3 {
private void calis() { try {
int sayilar[]={1,2,3,4};
for (int i = 0; i < 5; i++) {
System.out.println("--> " + sayilar[i]);
} } catch (ArrayIndexOutOfBoundsException
ex) { System.out.println("Hata
Yakalandi"); } }
public static void main(String[] args) {
System.out.println("Basla"); DiziErisim3
de3=new DiziErisim3(); de3.calis();
System.out.println("Bitti"); } }
|
Bu uygulama örneği ile DiziErisim2.java örneğimiz arasında sonuç bakımından
bir fark yoktur. Değişen sadece tasarımdır, try-catch bloğunun daha fazla kodu
kapsamasıdır.
İstisna İfadeleri
Bir yordam hangi tür istisna fırlatabileceğini önceden belirtebilir veya belirtmek
zorunda kalabilir. Bu yordamı (method) çağıran diğer yordamlar da, fırlatılabilecek
olan bu istisnayı, ya yakalarlar ya da bir üst bölüme iletirler. Bir üst
bölümden kasıt edilen, bir yordamı çağıran diğer bir yordamdır. Şimdi bir
yordamın önceden hangi tür istisna fırlatacağını nasıl belirtmek zorunda
kaldığını inceleyelim.
package makaleKod;
import java.io.*;
public class IstisnaOrnek1 {
public void cokCalis() { File f = new
File("ornek.txt"); BufferedReader bf = new BufferedReader( new FileReader(
f ) ); System.out.println(bf.readLine()); }
public void calis()
{ cokCalis(); }
public static void main(String args[]) {
IstisnaOrnek1 io1 = new IstisnaOrnek1(); io1.calis(); }
}
|
java.io paketinin içerisindeki sınıfları henüz incelemedik ama bu örneğimizde kullanılan
sınıfların ne iş yaptıklarını anlamak çok zor değil. Burada yapılan iş, aynı
dizinde bulunduğu farz edilen ornek.txt dosyasının ilk satırını okumaya
çalışmaktır. Yukarıdaki uygulamamızı derlemeye çalışırsak, derleyicinin bize
vereceği mesaj aşağıdaki gibi olur.
Biz diskimizde bulunduğu varsayılan bir dosyaya erişip onun ilk satırını okumaya
çalışmaktayız. Çok masum gibi gözüken ama tehlikeli istekler. Peki daha detaylı
düşünelim ve oluşabilecek olan istisnaları tahmin etmeye çalışalım.
İlk oluşabilecek olan istisna, o dosyanın yerinde olmayabileceğidir. Bu beklenmeyen
bir durum oluşturabilir, başka neler olabilir? Bundan ayrı olarak biz sanki o
dosyanın orada olduğundan eminmişiz gibi birde onun ilk satırını okumaya
çalışıyoruz, bu isteğimizde istisnaya sebebiyet verebilir çünkü dosya yerinde
olsa bile dosyanın ilk satırı olmayabilir. Dikkat ederseniz hep olasılıklar
üzerinde durmaktayım ama güçlü olasılıklar. Peki bu uygulamayı derlemenin bir
yolu yok mu?
Az önce bahsedildiği gibi bir yordam içerisinde oluşmuş olan istisnayı bir üst
bölüme yani o yordamı çağıran yordama fırlatabilir. Eğer bir istisna oluşursa
bu anlattıklarımıza göre bir yordamın iki şansı vardır diyebiliriz.
Birincisi oluşan bu istisnayı ya yakalayıp gereken işlemleri kendi içerisinde
sessizce gerçekleştirebilir veya bu istisna ile ben ne yapacağımı bilmiyorum
beni çağıran yordam düşünsün diyip, istisna nesnesini bir üst bölüme
fırlatabilir.
Aşağıdaki örnekte, oluşan istisnayı aynı yordamın içerisinde yakalanmaktadır; bu yüzden
yordamın hangi istisnayı fırlatabileceğini açıklamasına gerek yoktur. Bir
yordamın hangi tür istisnayı nasıl fırlatabileceğini açıklama olayını az sonra
göreceğiz ama önce aşağıdaki örneğimizi inceleyelim.
package makaleKod;
import java.io.*;
public class IstisnaOrnek2 {
public void cokCalis() { try {
File f = new File("ornek.txt"); BufferedReader bf=new BufferedReader(new
FileReader(f) ); System.out.println(bf.readLine()); } catch (IOException
ex) { System.out.println("Hata Yakalandi =" + ex); } }
public void calis() { cokCalis(); System.out.println("calis()
yordamı"); }
public static void main(String args[]) {
IstisnaOrnek2 io2 = new IstisnaOrnek2(); io2.calis(); System.out.println("main()
yordamı"); } }
|
Verilen örnekte, dosyaya erişirken veya ondan birşeyler okumak isterken oluşabilecek olan istisnalar; java.io.IOException istisna tipini kullanarak yakalanabilir. Zaten IstisnaOrnek1.java uygulamasının derlemeye çalışırken alınan hatadan hangi tür istisna tipinin kullanılması gerektiğini de çıkartabiliriz. java.io.FileNotFound Exception istina tipini, java.io.IOException tipi kullanılarak yakalanabilir bunun nasıl olduğunu biraz sonra göreceğiz.
Yukarıdaki uygulama güzel bir şekilde derlenir çünkü oluşabilecek olan tüm istisnalar için tedbir alınmıştır. Olayların akışını inceliyelim, bu uygulamayı çalıştırdığımız zaman (java IstisnaOrnek2) ilk olarak main() yordamından akışa başlanır. Daha sonra calis() yordamının ve cokCalis() yordamının çağrılması şeklinde akış devam ederken olanlar olur ve cokCalis() yordamının içerisinde istisna oluşur. Çünkü ornek.txt diye bir dosya ortalarda yoktur (yok olduğunu varsayın) ama olsun içimiz rahat çünkü try-catch hata yakalama mekanizmamız mevcuttur.
Olayın akışını açıklamaya başlayalım;
• Öncelikle akış, main() yordamının içerisinden başlar. Bu uygulamamızda main() yordamının içerisinden calis() yordamı çağrılmıştır.
• calis() yordamının içerisinden cokCalis() yordamı çağrılmıştır.
• cokCalis() yordamının içerisinde istisna oluşmuştur çünkü uygulamamızın yer aldığı dizinin içerisinde ornek.txt dosyası aranmış ve bulunamamıştır. Şimdi kritik an geldi, cokCalis() yordamının içerisinde try-catch mekanizması var mı?
• Evet, cokCalis() yordamının içerisinde try-catch mekanizması olduğu için, catch bloğuna yazılmış olan kodlar çalışır. Bu uygulamamızda ekrana " Hata Yakalandi =java.io.FileNotFoundException: ornek.txt (The system cannot find the file specified) " basılır, yani dosyanın olmayışından dolayı bir istisna olduğu belirtilir. Not: java.io.IOException istisna tipi, java.io.FileNotFound Exception istisna tipini kapsadığından bir sorun yaşanmaz bunun nasıl olduğunu biraz sonra inceleyeceğiz.
• Bitti mi? Tabii ki hayır, uygulamamız kaldığı yerden devam edecektir. Şimdi sıra calis() yordamının içerisindeki henüz çalıştırılmamış olan kodların çalıştırılmasına. Burada da ekrana "calis() yordamı" basılır.
• Son olarak akış main() yordamına geri döner ve main() yordamının içerisinde çalıştırılmamış olan kodlar çalıştırılır ve ekrana "main() yordamı" basılır.
• Ve uygulamamız normal bir şekilde sona erer.
Uygulamamızın toplu olarak ekran çıktısı aşağıdaki gibidir.
Akıllara şöyle bir soru gelebilir, "Eğer ornek.txt dosyası gerçekten olsaydı yine de try-catch mekanizmasını yerleştirmek zorundamıydık". Cevap evet, az önce bahseldiği gibi ortada istisna oluşma tehlikesi varsa bile bu tehlikenin önlemi Java programla dilinde önceden kesin olarak alınmalıdır.
İstisnaOrnek2.java uygulamamızda, oluşan istisna aynı yordamın içerisinde yakalanmıştır ve böylece uygulamanın akışı normal bir şekilde devam etmiştir. Peki oluşan bu istisnayı aynı yordamın içerisinde yakalamamak gibi bir lüksümüz olabilir mi? Yani oluşan istisna nesnesini -ki bu örneğimizde oluşan istisnamız java.io.FileNot FoundException tipindeydi, bir üst kısma fırlatılabilir mi? Bir üst kısma fırlatmaktan kasıt edilen, istisnanın meydana geldiği yordamı çağıran yordama bu istisna nesnesini fırlatmaktır. "Peki ama niye böyle bişeye ihtiyaç duyalım ki?" diyebilirsiniz. Bunun başlıca sebebi, istisnanın oluştuğu yordam içerisinde, o istisna nesnesi ile ne yapılabileceğinin bilenememesi olabilir. Bir üst kısımda elimizde daha fazla bilgi olabilir, ve bu bilgi çerçevesinde, elimizdeki istisna nesnesini daha güzel bir şekilde değerlendirip, uygulamanın akışını ona göre yönlendirebiliriz.
package makaleKod;
import java.io.*;
public class IstisnaOrnek3 {
public void cokCalis() throws
IOException{
File f = new File("ornek.txt"); BufferedReader bf=
new BufferedReader( new FileReader(f) ); System.out.println(bf.readLine());
}
public void calis() { try { cokCalis(); System.out.println("calis()
yordamı"); } catch(IOException ex) { System.out.println("Hata
Yakalandi-calis() =" + ex); }
}
public static void main(String
args[]) { IstisnaOrnek3 io3 = new IstisnaOrnek3(); io3.calis();
System.out.println("main() yordamı"); } }
|
IstisnaOrnek3.java örneğimizde oluşan istisna oluştuğu yordam içerisinde yakalanmamıştır. Peki nasıl olurda derleyici buna kızmaz, cevabı hemen aşağıdadır.
public void cokCalis() throws IOException { //..
}
|
Eğer bir istisna oluşursa, istisnanın oluştuğu yordamın yapacağı iki şey vardır demiştik. Birincisi oluşan istisnayı kendi içerisinde try-catch mekanizmasıyla yakalayabilir. İkincisi ise oluşacak olan istisnayı bir üst bölüme (kendisini çağıran yordama) fırlatabilir. Örneğin cokCalis() yordamı "throws IOException" diyerek, kendisini çağıran yordamlara şöyle bir mesaj gönderir, "Bakın benim içimde istisnaya yol açabilecek kod var ve eğer istisna oluşursa ben bunu fırlatırım, bu yüzden başınız çaresine bakın". Olayın akış şemasını anlatmaya çalışalım;
• Öncelikle akış, main() yordamının içerisinden başlar. Bu uygulamamızda main() yordamının içerisinden calis() yordamı çağrılmıştır.
• calis() yordamının içerisinden cokCalis() yordamı çağrılmıştır.
• cokCalis() yordamının içerisinde istisna oluşmuştur çünkü uygulamamızın yer aldığı dizinin içerisinde ornek.txt dosyası aranmış ve bulunamamıştır. Şimdi kritik an geldi, cokCalis() yordamının içerisinde try-catch mekanizması var mı?
• Hayır, cokCalis() yordamının içerisinde oluşan istisnayı yakalama mekanizması yoktur(try-catch) ama java.io.IOException tipinde bir hata nesnesi fırlatacağını "throws IOException" diyerek belirtmiştir. İstisna oluşmuş ve istisna nesnesi (java.io.IOException) bir üst bölüme yani calis() yordamına fırlatılmıştır.
• Artık istisna nesnemiz calis() yordamının içerisindedir, şimdi sorulması gereken soru " calis() yordamının içerisinde hata yakalama mekanizması var mıdır? "
• calis() yordamının içerisinde hata yakalama mekanizması vardır (try-catch) bu yüzden catch bloğunun içerisindeki kod çalıştırılır ve ekrana " Hata Yakalandi-calis() =java.io.FileNotFoundException: ornek.txt (The system can not find the file specified) " basılır, yani dosyanın olmayışından dolayı bir istisna olduğu belirtilir. Dikkat edilirse ekrana " calis() yordamı " basılmadı bunun sebebi istisnanın oluşmasından dolayı akışın catch bloğuna dallanmasıdır. Not: java.io.IOException istisna tipi, java.io.FileNotFoundException istisna tipini kapsadığından bir sorun yaşanmaz bunun nasıl olduğunu biraz sonra inceleyeceğiz.
• Son olarak akış main() yordamına geri döner ve main() yordamının içerisinde çalıştırılmamış olan kodlar çalıştırılır ve ekrana "main() yordamı" basılır.
• Ve uygulamamız normal bir şekilde sona erer.
Bu örneğimizdeki ana fikir, bir istisna kesin olarak oluştuğu yordamın içerisinde yakalanmayabileceğidir. Fırlatma özelliği sayesinde istisna nesnesi (eğer istisna oluşmuş ise) bir üst bölüme yani istisna oluşan yordamı çağıran yordama fırlatılabilir.
Peki bu istisna nesnesi (java.io.IOException) calis() yordamın yakalanmasaydı ne olurdu? Cevap: O zaman main() yordamın yakalanırdı. Nasıl? Hemen gösterelim.
package makaleKod;
import java.io.*; public
class IstisnaOrnek4 { public void cokCalis() throws IOException { File
f = new File("ornek.txt"); BufferedReader bf = new BufferedReader( new
FileReader( f ) ); System.out.println(bf.readLine()); } public
void calis() throws IOException { cokCalis(); System.out.println("calis()
yordamı"); } public static void main(String args[]) { try {
IstisnaOrnek4 io4 = new IstisnaOrnek4(); io4.calis(); System.out.println("main()
yordamı"); } catch(IOException ex) { System.out.println("Hata
Yakalandi-main() =" + ex); } }
}
|
Bu sefer biraz daha abartıp, oluşan istisna nesnesini son anda main() yordamında yakalıyoruz. Bu örneğimizde hem istisnanın meydana geldiği cokCalis() yordamı hem de calis() yordamı oluşan istisnayı fırlatmışlardır. Buraya kadar anlattıklarımızı adım adım açıklamaya çalışalım;
• Öncelikle akış, main() yordamının içerisinden başlar. Bu uygulamamızda main() yordamının içerisinden calis() yordamı çağrılmıştır.
• calis() yordamının içerisinden cokCalis() yordamı çağrılmıştır.
• cokCalis() yordamının içerisinde istisna oluşmuştur çünkü uygulamamızın yer aldığı dizinin içerisinde ornek.txt dosyası aranmış ve bulunamamıştır. Şimdi kritik an geldi, cokCalis() yordamının içerisinde try-catch mekanizması var mı?
• cokCalis() yordamının içerisinde oluşan istisnayı yakalama mekanizması yoktur (try-catch) ama java.io.IOException tipinde bir hata nesnesi fırlatacağını "throws IOException" diyerek belirtmiştir. İstisna oluşmuş ve istisna nesnesi (java.io.IOException) bir üst bölüme yani calis() yordamına fırlatılmıştır.
• Artık istisna nesnemiz calis() yordamının içerisindedir, şimdi sorulması gereken soru " calis() yordamının içerisinde hata yakalama mekanizması var mıdır? "
• Cevap hayırdır. calis() yordamı da oluşan istisna nesnesini bir üst bölüme yani kendisini çağıran main() yordamına fırlatmıştır.
• İstina nesnemiz main() yordamının içerisine geldi. Sorulması gereken soru " main() yordamının içerisinde hata yakalama mekanizması var mıdır? "
• Cevap evettir. Böylece akış main() yordamının içerisindeki catch bloğuna dallanır ve catch bloğunun içerisindeki kod çalıştırılır.
• Ve uygulamamız normal bir şekilde sona erer.
Uygulamanın toplu olarak çıktısı aşağıdaki gibidir.
Oluşan bir istisna nesnesini catch bloğunda yakalamanın ne gibi avantajları olabilir? Bu sorunun cevabına değinmeden
önce olaylara eğer istisna nesnesi main() yordamında yakalanmasaydı neler olacağını inceleyerek başlayalım.
package makaleKod;
import java.io.*; public
class IstisnaOrnek5 { public void cokCalis() throws IOException { File
f = new File("ornek.txt"); BufferedReader bf = new BufferedReader( new
FileReader(f)); System.out.println(bf.readLine()); } public void
calis() throws IOException { cokCalis(); System.out.println("calis()
yordamı"); } public static void main(String args[]) throws IOException
{ IstisnaOrnek5 io5 = new IstisnaOrnek5(); io5.calis(); System.out.println("main()
yordamı"); } }
|
Görüldüğü üzere cokCalis() yordamının içerisinde oluşan istisna hiçbir yordam içerisinde hata yakalama mekanizması kullanılarak yakalanmamıştır (try-catch). Bunun yerine tüm yordamlar bu istisna nesnesini fırlatmayı seçmiştir, buna main() yordamıda dahildir. Böyle bir durumda akışın nasıl gerçekleştiğini, adım adım anlatmaya çalışalım;
• Öncelikle akış, main() yordamının içerisinden başlar. Bu uygulamamızda main() yordamının içerisinden calis() yordamı çağrılmıştır.
• calis() yordamının içerisinden cokCalis() yordamı çağrılmıştır.
• cokCalis() yordamının içerisinde istisna oluşmuştur çünkü uygulamamızın yer aldığı dizinin içerisinde ornek.txt dosyası aranmış ve bulunamamıştır. Şimdi kritik an geldi, cokCalis() yordamının içerisinde try-catch mekanizması var mı?
• cokCalis() yordamının içerisinde oluşan istisnayı yakalama mekanizması yoktur (try-catch) ama java.io.IOException tipinde bir hata nesnesi fırlatacağını "throws IOException" diyerek belirtmiştir. İstisna oluşmuş ve istisna nesnesi (java.io.IOException) bir üst bölüme yani calis() yordamına fırlatılmıştır.
• Artık istisna nesnemiz calis() yordamının içerisindedir, şimdi sorulması gereken soru " calis() yordamının içerisinde hata yakalama mekanizması var mıdır? "
• Cevap hayırdır. calis() yordamı da oluşan istisna nesnesini bir üst bölüme yani kendisini çağıran main() yordamına fırlatmıştır.
• İstina nesnemiz main() yordamının içerisine geldi. Sorulması gereken soru " main yordamının içerisinde hata yakalama mekanizması var mıdır? "
• Cevap hayırdır. Peki ne olacak? Çok basit, uygulama doğal olarak sonla-nacaktır.
Uygulamanın toplu olarak çıktısı aşağıdaki gibidir.
"Hata yakalama mekanizması koyduğumuzda da uygulama sonlanıyordu, şimdide sonlandı bunda ne var ki" diyebilirsiniz. Haklı olabilirsiniz ama önce oluşan bir istisna nesnesi catch bloğunda yakalamanın ne gibi avantajları olabilir?
Oluşan bir istisna nesnesini catch bloğundan yakalamak, daha doğrusu hata yakalama mekanizması kullanmak uygulamayı yazan kişilere büyük kolaylıklar sağlar. En büyük avantaj oluşan hatayı catch bloğunun içerisinde kaydedilirsiniz (logging) (dosyaya ama veri tabanına... gibi gibi...) . Örneğin iyi işleyen bir uygulama yazdınız ve bu uygulama yaptığınız tüm -daha doğrusu aklınıza gelen- testlerden geçmiş herşey harika, kendinize güveniniz gelmiş, dünya gözünüze artık bambaşka bir yer gibi geliyor ama bir gün bir bakıyorsunuz ki uygulamanız çalışması durmuş!! ilk yapacağınız şey "bu uygulamayı kim kapattı!" diye etrafa sormak oysaki kimsenin günahı yok, kimse elini uygulamanıza sürmemiştir zaten böyle bir riski kim alabilir ki? Asıl gerçek, uygulamada ters giden bir
şey olmuş ve uygulama kapanmıştır. İşte tam o anda tutunacağınız tek dal dosyaya veya veri tabanına kayıt ettiğiniz hata mesajlarıdır. Bu bakımdan catch bloğunun içerisine oluşan hata ile alakalı ne kadar detaylı bilgi gömerseniz, bu bilgi sizi ileride -eğer hata oluşursa- o kadar yardımcı olacaktır.
IstisnaOrnek5.java kötü bir uygulama örneğidir. Oluşabilecek olan bir istisna, hata yakalama mekanizması (try-catch) ile sizin öngördüğünüz bir yerde yakalanmalıdır. Bir istisna meydana geldiği zaman uygulama mutlaka sonlanmak zorunda değildir. Eğer bir telafisi var ise bu catch bloğunun içerisinde yapılmalı ve uygulama tekrardan ayağa kaldırılmalıdır ama çok ölümcül bir hata ise o zaman hata mesajını kaydetmekten (dosyaya veya veri tabanına.. gibi gibi...) başka yapılacak pek fazla
bir şey yoktur.
İstisna Tip Hiyerarşisi
Nasıl olurda java.io.IOException istisna tipi, java.io.FileNotFoundException istisna tipini kapsayabilir? Kapsamak ne demektir? Kapsamak demek, eğer uygulamanızda java.io.FileNotFoundException tipinde bir istisna nesnesi oluşmuşsa (bir istisna oluşmuşsa) bu istisna tipini java.io.IOException tipini kullanarak da catch bloğunda yakalayabileceğiniz anlamına gelir.
Yukarıdaki şemamızdan görüleceği üzere, FileNotFoundException istisna tipi, IOException istisnasının alt kümesi olduğu için, FileNotFoundException tipinde bir istisna nesnesini catch bloğunun içerisinde IOException istisna tipiyle yakalayabiliriz.
Throwable istisna nesnesi, tüm istisna nesnelerinin atasıdır. Yukarıdaki şemamızıa bakarak istisnaları 3 gruba ayırabiliriz.
• Error istisna tipi ölümcül bir hatayı işarettir ve telafisi çok zordur, neredeyse imkansızdır. Örneğin OutOfMemoryError (yetersiz bellek) istisnası oluşmuş ise uygulamanın buna müdahele edip düzeltmesi imkansızdır.
• RuntimeException istisna tipleri, eğer uygulama normal seyrinde giderse ortaya çıkmaması gereken istisna tipleridir. Örneğin ArrayIndexOutOfBoundsException istisna tipi, bir dizinin olmayan elemanına eriştiğimiz zaman ortaya çıkan bir istisnadır. RuntimeException istisna tipleri, kontrolsüz kodlamadan dolayı meydana gelen istisna tipleri diyebiliriz. Biraz sonra bu istisna tipini detaylı biçimde inceleyeceğiz.
• Ve diğer Exception tipleri. Bu istisna tipleri çevresel koşullardan dolayı meydana gelebilir. Örneğin erişmeye çalışan dosyanın yerinde olmaması (FileNotFoundException) veya network bağlantısının kopması sonucu ortaya çıkabilecek olan istisnalardır ve bu istisnalar için önceden bir tedbir alınması şarttır.
Tüm Diğer Exception İstisna Tiplerini Yakalamak
Bir uygulama içerisinde oluşabilecek olan tüm istisna tiplerini yakalamak için aşağıdaki ifadeyi kullanabilirsiniz.
catch (Exception ex) { //...... }
|
Tüm istisnaları yakalamak (Error, RuntimeException ve diğer Exception türleri) için Throwable istisna tipini kullanmak iyi fikir değildir. Bunun yerine bu üç gruba ait daha özellikli istisna tiplerinin kullanılmasını önerilir.
RuntimeException İstisna Tipleri
DiziErisim.java uygulama örneğimiz içerisinde istisna oluşma riski olmasına rağmen nasıl oldu da Java buna kızmayarak derledi? Peki ama IstisnaOrnek1.java uygulamasını niye derlemedi? Bu soruların cevapları istisna tiplerinin iyi bilenmesi ile ortaya çıkar.
DiziErisim.java uygulama örneğinde istisna oluşma riski vardır. Eğer uygulamayı yazan kişi dizinin olmayan bir elemanına erişmeye kalkarsa ArrayIndexOutOfBounds Exception hatası alacaktır, yani RuntimeException (çalışma-anı hatası). Peki bunun sebebi nedir? Bunun sebebi kodu yazan arkadaşın dikkatsizce davranmasıdır. Bu tür hatalar derleme anında (compile-time) fark edilemez. Java bu tür hatalar için önceden bir tedbir alınmasını şart koşmaz ama yine de tedbir almakta özgürsünüzdür. Bir dosyaya erişirken oluşacak olan istisnaya karşı bir tedbir alınmasını, Java şart koşar çünkü bu tür hatalar diğer Exception istisna tipine girer. Genel olarak karşılaşılan RuntimeException istisna türlerine bir bakalım;
• AritmeticException: Bir sayının sıfıra bölünmesiyle ortaya çıkabilecek olan bir istisna tipidir.
• NullPointerException: Bir sınıf tipindeki referansı, o sınıfa ait bir nesneye bağlamadan kullanmaya kalkınca alınabilecek bir istisna tipi.
String ad == null; // NullPointerException ! hata !
System.out.println("Ad = " + ad.trim() );
|
Bu hatayı almamak için,
String ad = " Java Makale Projesi "; // baglama
islemi System.out.println("Ad = " + ad.trim() ); //dogru // NullPointerException ! hata !
|
• NegativeArraySizeException: Bir diziyi negatif bir sayı vererek oluşturmaya çalışırsak, bu istisna tipi ile karşılaşırız
// NegativeArraySizeException ! hata !
int dizi[] = new dizi[ -100 ];
|
• ArrayIndexOutOfBoundsException: Bir dizinin olmayan elemanına ulaşmak istendiği zaman karşılaşılan istisna tipidir
• SecurityException: Genellikle tarayıcı (browser) tarafından fırlatılan bir istisna tipidir. Bu istisnaya neden olabilecek olan sebepler aşağıdaki gibidir;
• Applet içerisinden, yerel (local) bir dosyaya erişilmek istendiği zaman.
• Appletin indirildiği sunucuya (server) değilde değişik bir sunucuya bağlantı kurulmaya çalışıldığı zaman.
• Applet içerisinde başka bir uygulama başlatmaya çalışıldığı zaman.
SecurityException istisna tipi fırlatılır.
Önemli noktayı bir kez daha vurgulayalım, RuntimeException ve bu istisna tipine ait alt tipleri yakalamak için, Java derleme anında (compile-time) bizlere bir bir zorlama yapmaz.
Bu makalemizde genel olarak javada istisnalar kavramına giriş yapmaya çalıştık. Bir sonraki java makalemizde istisnalar konusunu
incelemeye devam edeceğiz.
Umarım yararlı olmuştur.
Uygulamada bahsettiğimiz sınıfların kaynak kodlarına linkten erişebilirsiniz.
Turhal Temizer
http://turhal.blogspot.com
Kaynaklar
KTÜ İSBB ders notları
Makale:
Java - Exceptions ( İstisnalar ) J# ve Java dili Turhal Temizer
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|
|