try catch finally kullanımında dikkat edilmesi gereken hususlar

exception, java June 19th, 2008

selam manyaklar, bir süredir bu konuyu yazmayı düşünüyodum, çünkü try catch blokları herkesin bildiği zannettiği ancak yanlış kullanımlarda vahim sonuçlar doğuran, doğru kullanılması, gereken yerde gereken istisnaların yakalanması, finally blokları önemli olan konular.

bildiğiniz üzre java’da hata yakalama için c++’dan tanıdığımız try catch blokları var. bu bloglar özetle try içerisindeki kodda istisnati durum oluştuğu zaman (Exception) bunu uygun catch bloğunda yakalar ve bizim bu hata durumu olduğunda catch bloğu içine yazdığımız kodun çalışması sağlanır. nasıl mı,


try {
hede();
} catch (Exception e) {
System.out.println("hata oldu!");
}

bu örnek kodda hede() metodu içerisinde istisnai durum olursa (Exception atarsa deriz) catch bloğu bunu yakalar ve ekrana “hata oldu!” yazar. yani hata oluştuğu durumda bu kod çalışır ve biz de gerekli işlemleri yaparız.

catch bloğu içersinde hangi tipteki Exception’ları yakalayacağımızı belirtiyoruz, bu örnekte Exception sınıfında veya bu sınıftan türemiş tüm tipteki exception’ları yakalayabiliriz. ancak burada oluşacak hatanın tipine göre uygun exception’ı yazmak her zaman daha iyidir. örnek:


try {
hede();
} catch (NullPointerException e) {
System.out.println("nal gibi hata oldu!");
} catch (NumberFormatException e) {
System.out.println("bi numara var ama du bakalım");
}

bu örnekte hede() metodunun içinde NullPointerException tipinde bir hata olursa bu hata buraya düşer. aynı şekilde NumberFormatException olursa o da ilgili bloğa. bunların dışında bir hata oluşursa bu bloklarda yakalanmaz, o yüzden belki (gerekliyse) en sona bir catch (Exception e) eklenebilir.

genel olarak try catch bu şekilde, bir de bunların kankası finally bloğu var:

try {
hede();
} catch (NullPointerException e) {
System.out.println("nal gibi hata oldu!");
} finally {
System.out.println("bunu yep yapiyorum");
}

finally bloklarının özelliği, exception olsa da olmasa da çalışacak olmasıdır. öyle ki boğaziçi bilgisayar mühendisliğinden mezun bir arkadaşın deyişi ile bu bloklar “elektrik kesilse bile” çalışır :)

finally bloklarının esas amacı, try bloğunun başında bir kaynağı açıp, işimiz bittiğinde kapatırken ortaya çıkıyor. daha iyi anlatabilmek için, aslen bu yazının konusunu oluşturan, bir çok kereler rastladığım hatalardan, gerçek hayata dair birkaç örnek vermek istiyorum;


try {
Connection con = ConnectionManager.getInstance().getConnection();
CallableStatement stmt = con.prepareCall("{ call hedey() }");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
// bişey bişey
}
rs.close();
stmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}

şimdi bu kodu incelediğimizde, kodu yazan kişi veritabanı bağlantısını almış, statement ile resultset içerisine verileri doldurmuş, işi bitince de kapatmış. kendince exception handling’ini de yapmış. ancak durum böyle değil. her ne kadar connection’ı kapatmayan arkadaşların kodlarınından daha iyi olsa da burda bir hata var. eğer stmt.executeQuery() metodu çalıştırılırken bir Exception olursa (ki olmayacak bişey değil) kod direk catch bloğundan devam eder. bu durumda açmış olduğumuz statement ve connection kapanmaz ve bir süre sonra too many connection hatasını afiyetle yirsiniz.

bir başka benzer hata, oldukça yaygın olarak şu şekilde yapılıyor:


try {
Connection con = ConnectionManager.getInstance().getConnection();
CallableStatement stmt = con.prepareCall("{ call hedey() }");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
// bişey bişey
}} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}

buradaki doğru yaklaşılmış ancak bir ayrıntı unutulmuş. kaynaklar finally bloğu içinde kapatıldığı için try bloğunda bir sorun olduğunda kaynaklar burada kapatılır. ancak kaynakların kapatılma işlemi tek bir try catch bloğunda yapıldığından burada örneğin rs.close() da bir hata oluştuğunda, statement ve connection kapatılamadan catch bloğuna gider. yani bir önceki koddan bir farkı olmaz.

bu tarz sorunların çözümü düzenli olarak tomcat’i restart etmek değil elbette :) işte yapılması gereken şudur:


try {
Connection con = ConnectionManager.getInstance().getConnection();
CallableStatement stmt = con.prepareCall("{ call hedey() }");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
// bişey bişey
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
if (stmt != null) stmt.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
if (con != null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}

burada kaynakların kapatma işlemi finally bloğu içersinde yapılıyor, her bir kaynak da ayrı ayrı hata kontrolüne tabi tutuluyor. işte olması gereken budur. (budur abi :))

bundan başka, java dilinde diğer dillerden (c++, c# vs) farklı (bence üstün) bir yönü olarak, metodlar Exception atabilir ve bu metodları çağıran sınıfların da bu Exception’ları yakalaması zorunludur. nasıl mı;


public void hede() throws Exception
{
// ...
}

bu metodu çağıran herkesin bu metodu try catch içine alması gerekir. ya ne gerek var bunlara demeyin. (ben de öyle diyodum baştan sonradan anladım mevzuyu) ikinci önemli konu da burada devreye giriyor, metodlar Exception atıyor diye onu çağırdığınız yerde “catch edeyim gitsin” diyerek kod yazmamanız gerekiyor çünkü burada yakaladığımız Exception’ın aslen burada bir anlamı yok. eğer burada catch işlemi yaparsak bu sefer metod’un hatalı hatasız çalıştığını onu çağıran koda gönderebilmesi için geri dönüş değeri falan kullanmamız gerekir ki bu da hiç oop’a uygun bir davranış değil. toparlamakta zorluk çekiyorum o yüzden bir örnek vermeye çalışayım,


public void islemYap() throws Exception
{
// bişey bişey
}

public boolean islemleriYaptir()
{
try {
dbyebaglan();
islemYap();
islemYap();
} catch (Exception e) {
return false;
} finally {
dbyigapa();
}
return true;
}

public void hesapla() {
if (islemleriYaptir()) {
System.out.println(”islemler basariyla tamamlandi”);
} else {
System.out.println(”islemler basarisiz oldu”);
}
}
işte bu tarz bir yaklaşım try catch bloklarını doğru kullanamamış oluyor. oysa ki bu kod aşağıdaki gibi olabilir:


public void islemYap() throws Exception
{
// bişey bişey
}


public void islemleriYaptir() throws Exception
{
try {
dbyebaglan();
islemYap();
islemYap();
} finally {
dbyigapa();
}
}


public void hesapla() {
try {
islemleriYaptir();
System.out.println("islemler basariyla tamamlandi");
} catch (Exception e) {
System.out.println("islemler basarisiz oldu");
}
}

burada işlemler gene yapılıyor, resource’lar finally bloğunda kapatılıyor ancak oluşabilecek istista, en yukarı kadar taşınıyor.

java diğer dillerden farkını burada koyuyor, metodlardan gelebilecek hataları yakalamaya bizi zorlayarak hatasız kod yazmamıza yardımcı oluyor. geriye kalan da bizim bu özellikleri doğru kullanıp süt gibi kod yazmamız o kadar.

yazıda eksik hatalı şeyler olmadığını umut ederek herkese Exception’sız günler dilerim…

(not: ClassNotFoundException’a gıcığım)


Social Bookmarking
Add to: Mr. Wong Add to: Digg Add to: Del.icio.us Add to: Reddit Add to: StumbleUpon Add to: Slashdot Add to: Netscape Add to: Furl Add to: Yahoo Add to: Google Add to: Technorati Add to: Newsvine Add to: Ma.Gnolia



Başka Manyak Konular


Lütfen Yorumlarınızı bizimle paylaşın.

3 Responses to “try catch finally kullanımında dikkat edilmesi gereken hususlar”

  1. try catch finally kullanımında dikkat edilmesi gereken hususlar Says:

    […] http://java.manyaklari.org/2008/06/try-catch-finally-kullaniminda-dikkat-edilmesi-gereken-hususlar.j… […]

  2. jasfid Says:

    try catch kodu yavaşlatır mı?

  3. elix Says:

    try blogunun büyük olması yavaşlatıyor sanırım. Ondan dolayı sadece hata oluşacak satırı try bloguna almak uygun hareket olsa gerek.

    Makaledeki kod kısımları için daha düzgün görünen birşeyler ayarlarsanız güzel olurdu.

Leave a Reply

Site Navigation

Categories

Archives

Meta

Recent Enteries

Recent Comments

FireStats iconPowered by FireStats