Yazılım gerçek dünyada var olan somut/soyut süreçlerin bilgisayar donanımı üzerinde çalıştırılan benzetimleridir. Amaç, sürecin, etkileşimde bulunulan diğer süreçler ile birlikte daha verimli ve sağlıklı bir şekilde işletilmesini sağlamaktır. Mesela, bir otomasyon yazılımı zayiatı azaltmak ve bakımı hızlandırmak suretiyle parçası olduğu üretim sürecinin daha verimli olmasını sağlayacaktır. Doğal olarak, bir yazılımın başarılı kabul edilmesindeki en önemli ölçüt, bilgisayarda oluşturulan hesaplama sürecinin benzetimi yapılmakta olan sürecin algılanışına1 sadık kalıp kalmadığı şeklinde ifade edilebilecek doğruluk (İng., correctness) özelliğidir. Peşinden koşulması gereken bir diğer özellik, yazılımın öngörülmeyen koşullar altında da kabul edilebilir bir tepki göstermesi olarak da tanımlayabileceğimiz dayanıklılıktır (İng., robustness). Bu beklentiler yazılım sektörünün rekabete dayalı pragmatik bir dünya olması gerçeği ile birlikte ele alındığında, yazılım üreticisinin birincil görevinin düzgün bir peformansa sahip, doğru ve dayanıklı—yani, güvenilir (İng., reliable)—programların makul bir hızda geliştirilmesi olduğu söylenebilir. İşte bu yazıda, ifade edilen görev tanımındaki güvenilirlik özelliğine yönelik olarak Java programlama dili tarafından sağlanan desteğe değineceğiz.
Kötü bir haber vererek başlayalım: Java, programlarınızın doğruluğunu sağlamak bağlamında kaynak kodunuzun dilin yazım kurallarına uygunluğunu denetlemek dışında pek bir destek sağlamaz; sözdizimsel hataların ötesinde Java derleyicisinin yapacağı çok şey yoktur. Aşağıdaki örnek üzerinden ne demek istediğimizi açalım.
Kotarımın sorunun çıktığı nokta yerine çağrı yığıtındaki diğer metotlara bırakıldığı metot başlığına eklenen
Peki, ya sizin ve kullanıcının iradesi dışında gelişen sebepler nedeniyle programınız göçecek olursa. Mesela, arkadaşınız ortaklaşa kullandığınız bilgisayardan programınızın çalışması için gerekli olan bir sınıf dosyasını silecek olursa, ne olur? Ya da, dosyanın diskte kaydedildiği sektörlerden birinin bozulması nedeniyle sınıf dosyasının okunarak içselleştirilmesi söz konusu olamazsa, ne olur? Ya da ya da, programınızın işlemesi için gereksinilen kaynaklar JSM tarafından sağlanamayacak kadar büyük olmaya başlarsa, ne olur? Gelin bu soruların yanıtını
Bu ana kadarki bilgilerimizi maddeleyerek özetleyecek olursak aşağıdaki listeyi elde ederiz. Java programları, iç ve dış koşullara göre beklenenden farklı bir şekilde davranabilir. Davranış sapması programcının müdahele edemeyeceği dış kaynaklardan ötürüyse, programcı
Hangi kategoriye giriyor olursa olsun, programcı tüm koşullar altında elinden gelenin en iyisini sergilemelidir. Mümkünse, kotarıcıdaki kod ile programın sağlıklı bir şekilde devamı sağlanmalı, bu mümkün olmuyorsa, nasıl olsa bir şey yapamıyorum, denilerek oturmaktansa programın zarif bir şekilde bitmesi için elden gelen yapılmalıdır. Mesela, kullanılmakta olan dış kaynaklar kotarıcıda döndürülmeli, programın bakıcısının muhtemel bir programlama hatasını bulmasını kolaylaştırmak adına bir seyir defterine neden ile ilgili bilgiler not düşülmelidir. Bu noktada karşımıza, ayrıksı durum oluşsa da oluşmasa da çalıştırılacak kodu içeren bir kotarıcı olarak
Kod parçasında dikkat çekilmesi gereken bir diğer nokta, kotarıcıların yerleştiriliş sırasının önemli olduğudur. Bir kotarıcı sadece argümanındaki sınıfa ait nesneleri değil, o sınıfın kökü olduğu sıradüzeni içindeki tüm sınıfların nesnelerini yakalar. Örneğin, yukarıdaki ilk kotarıcı
Evet, geldik kendi ayrıksı durumunu kendin pişirmeye. Ama, yazımızın vardığı uzunluğu ve muhtemel konsantrasyon azalmasını düşünerek bunu bir başka yazıya bırakalım. Onun için, şimdilik bu kadar. Unutmayın, hatasız program(cı) olmaz; birazcık defansif programlama ortaya çıkabilecek zararın faturasını azaltır. Onun için sadece doğruluk değil, dayanıklılığa da önem verin. Yani, güvenilir yazılım üretin.
Kötü bir haber vererek başlayalım: Java, programlarınızın doğruluğunu sağlamak bağlamında kaynak kodunuzun dilin yazım kurallarına uygunluğunu denetlemek dışında pek bir destek sağlamaz; sözdizimsel hataların ötesinde Java derleyicisinin yapacağı çok şey yoktur. Aşağıdaki örnek üzerinden ne demek istediğimizi açalım.
Faktöryel.java
import static java.lang.System.out; ... public class Faktöryel { public static void main(String[] ksa) { byte b = Byte.parseByte(ksa[0]); out.println(b + "!: " + fakt(b)); ... } // void main(String[]) sonu public static long fakt(byte n) { long çarpım = 1; for (byte i = 2; i <= n; i++) çarpım += i; return çarpım; } // long fakt(byte) sonu ... } // Faktöryel sınıfının sonu
$ javac -encoding UTF-8 Faktöryel.java $ java Faktöryel 5 5!: 15 ✘Görüldüğü gibi, sözdizimsel bir hata bulunmamakla birlikte, faktöryel kavramının hatalı gerçekleştiriminden kaynaklanan bir mantıksal hata ortaya çıkmıştır. Derleyicinin müdahele ederek işaretli satırdaki
+
yerine *
yazılması gerektiği yorumunu yapması olanaksızdır. Bu gibi hataların, kodun sınanması sırasında keşfedilerek programcı tarafından ortadan kaldırılması gerekir. Bir an için bunun yapıldığını ve hatanın düzeltilerek doğru bir gerçekleştirimin sağlandığını düşünelim. Bu durumda, programımızın çalıştırılması aşağıdaki sonuçları verecektir.
$ java Faktöryel 5 5!: 120 ✔ $ java Faktöryel 20 20!: 2432902008176640000 ✔ $ java Faktöryel 21 21!: -4249290049419214848 ✘Bir ihtimal Java'daki tamsayı türlerinin taşma davranışını bilmeyenleriniz, herhangi bir sayının eksi değerli bir faktöryele sahip olduğuna şaşırabilir. Bu gruptaki arkadaşlara önerim, daha fazla ilerlemeden şu yazıya🔎 bir göz atmaları. Diğer arkadaşlar ise, bunun sebebinin çarpım sonucunun
long
değerler için söz konusu olan aralığa düşmemesi nedeniyle kırpılması olduğunu bileceklerdir. Peki bu durumda, faktöryel metodumuzun doğru olmadığını söyleyebilir miyiz? Faktöryelin tanımını bilen herkesin bu soruya hayır yanıtı vermesi gerekir; ortada olan şey bir hatadan çok yetersizliktir ve muhtemelen metodun kullanıcısı ile iletişim eksikliğinden kaynaklanmaktadır. Soruna değişik şekillerde çözüm getirilebilir.
- Gerçekleştirime dokunulmaz ve kullanıcıya sağlanan belgelerde metodun 0 ile 20 arasındaki tamsayılar için doğru çözümler ürettiği ve dolayısıyla sağlanması beklenen argüman değerinin bu aralıkta olması gerektiği söylenir.
- Duruma has bir başka çözüm sağlanarak eksiklik giderilir. Örneğimizde, dönüş türü olarak
long
yerinejava.math.BigInteger
türünün kullanılması ve kodda buna göre değişikliklerin yapılması işimizi görecektir. - Geçirilen argüman değerinin beklenen aralıkta olup olmadığı denetlenir. Bu, basit bir
if
komutuyla yapılabileceği gibi doğruluk savı (İng.; assertion) denetimiyle de yapılabilir. İlk yolun seçilmesi durumunda, görülen olumsuzluk dönüşte [0 gibi] özel olarak yorumlanan bir değerle belirtilebileceği gibi söz konusu durumu özetleyen bir ayrıksı durum (İng., exception(al condition)) nesnesi ile de bildirilebilir.
IllegalArgumentException
türündeki bir ayrıksı durum nesnesi ile bildirilirken, argümanın 0 veya 1 olması halinde 1, geri kalan durumlarda ise matematikten tanıdık n * (n-1)!
değeri döndürülmektedir. java.lang
paketinde tanımlanan IllegalArgumentException
, sağlanan argüman değerinin, -5'in faktöryelinin bulunmaya çalışılmasında olduğu gibi, uygunsuz olduğuna işaret eder.
... import java.math.BigInteger; public class Faktöryel { public static void main(String[] ksa) { ... long l = Long.parseLong(ksa[1]); try { out.println(l + "!: " + fakt2(l)); } catch(IllegalArgumentException a) { out.println(l + "!: " + fakt2(Math.abs(l)) + "!!!"); } } // void main(String[]) sonu ... public static BigInteger fakt2(long n) { if (n < 0) throw new IllegalArgumentException(String.valueOf(n)); if (n < 2) return BigInteger.ONE; else return BigInteger.valueOf(n) .multiply(fakt2(n - 1)); } // BigInteger fakt2(long) sonu } // Faktöryel sınıfının sonu
$ java Faktöryel 21 21 21!: -4249290049419214848 ✘ 21!: 51090942171709440000 ✔ $ java Faktöryel 5 -5 5!: 120 ✔ -5!: 120!!!Beklenmedik koşulların oluştuğu noktada, özet bilgi içeren bir ayrıksı durum nesnesinin yaratılıp
throw
komutu ile fırlatılması gerekir. Bunun sonrasında, ortaya çıkan durumun çözümünü bilen birisinin duruma el atıp bir şeyler yapması beklenir. Biraz düşünüldüğünde, çözümün içine düşülen duruma sebep olanlar tarafından sağlanabileceği görülecektir. Bu ise, ayrıksı durumun ortaya çıktığı noktaya gelinene kadar izlenen çağrı zinciri üzerindeki noktalar demektir. Bir diğer deyişle, çare ya sorunun ortaya çıktığı noktada ya da o noktaya gelinmesi ile son bulan çağrı yığıtındaki diğer metotlarda bulunabilir. Çözüme dair bir şeyler yapabileceğini düşünenlerin bu iddialarını try
-catch
yapısı içinde bildirmeleri beklenir. try
, takip eden kıvrımlı ayraç çifti arasındaki komutların sorun çıkarabileceğini bildirirken, kotarıcı olarak adlandırılan catch
bloğu/blokları iliştirildikleri korumalı bölgede ortaya çıkabilecek sorunların tümü veya bazıları için çözümler sunar. Çağrı zinciri üzerindeki noktaların hiçbirinde çözüm önerilmemesi halinde ise, top denetim akışı geriye sarılarak programı başlatan JSM'ye atılacak ve JSM de ortaya çıkan durumu oluştuğu yerden başlayarak nerelere uğrayarak çözmeye çalıştığını söyleyen bir raporu standart hata ortamına2 yazarak programı sonlandıracaktır. Bunun nasıl olduğuna aşağıdaki çıktıya göz atarak bir bakalım.
... public class Faktöryel { public static void main(String[] ksa) { ... long l = Long.parseLong(ksa[1]); out.println(l + "!: " + fakt2(l)); } // void main(String[]) sonu ... public static BigInteger fakt2(long n) { if (n < 0) throw new IllegalArgumentException(String.valueOf(n)); ... } // BigInteger fakt2(long) sonu } // Faktöryel sınıfının sonu
$ java Faktöryel 5 -5 5!: 120 ✔ Exception in thread "main" java.lang.IllegalArgumentException: -5 at Faktöryel.fakt2(Faktöryel.java:20) at Faktöryel.main(Faktöryel.java:9)JSM'ye bakılacak olursa, programın [main adına sahip] ana izleğinde
Faktöryel
sınıfının main
metodu içinden 9. satırda aynı sınıftaki fakt2
metodu çağrılmış ve denetim akışı bu metottta iken 20. satırda IllegalArgumentException
ayrıksı durumu ortaya çıkmış. Anlamadıysanız ikinci bir örnekle açıklık getirmeye çalışalım; anlayanlar da bu sayede pekiştirmiş olurlar.
import java.io.BufferedReader; import java.io.FileReader; import java.util.Scanner; public class Örnek { public static void main(String[] ksa) { // ... m1(); // ... } // void main(String[]) sonu private static void m1() { // ... m2(); // ... } // void m1() sonu private static void m2() { String dosyaAdı; Scanner grdKanalı = new Scanner(System.in); System.out.print("Dosya adını giriniz: "); dosyaAdı = grdKanalı.nextLine(); // ... m3(dosyaAdı); // ... } // void m2() sonu private static void m3(String dosyaAdı) { BufferedReader dosya = new BufferedReader(new FileReader(dosyaAdı)); // ... } // void m3(String) sonu } // Örnek sınıfının sonuİşaretli satırlarda, argümanda geçirilen ada sahip ve o anki çalışma dizini içinde bulunan bir dosyanın tamponlanarak ve karakter yönelimli bir biçimde okunması için uygun türden bir akak nesnesi yaratılıyor. Bu işlem, sağlanan ada sahip bir dosyanın bulunmaması halinde
java.io.FileNotFoundException
ayrıksı durumu ile sonlanacaktır. Dolayısıyla, programın derlenip var olmayan bir dosyanın adı verilerek çalıştırılması, yukardakine benzer bir çağrı yığıtı özetinin üretilmesine neden olacaktır diye düşünebiliriz. Ancak, gelin görün ki, program derlendiğinde durumun hiç de öyle olmadığı görülür.
$ javac -encoding UTF-8 Örnek.java Örnek.java:29: error: unreported exception FileNotFoundException; must be caught or declared to be thrown new BufferedReader(new FileReader(dosyaAdı)); ^ 1 errorYukarıdaki çıktıdan da görülebileceği gibi,
IllegalArgumentException
için sesini bile çıkarmayan derleyici, iş FileNotFoundException
'a geldiğinde yaygarayı basmaktadır. Çifte standardın sebebi, ayrıksı durumların iki kategoriye ayrılmasıdır:
RuntimeException
köklü sınıf sıradüzeninde olanlar: Bu kategoriye giren ayrıksı durumlar, ya ortaya çıktıkları noktada yakalanıp kotarılmalı ya da çağrı yığıtındaki diğer metotlardan birinde kotarılması gerektiğini hatırlatmak için metot imzasında ilan edilmelidirler.- Diğerleri: Bu ayrıksı durumların ne yakalanması ne de, yakalanmadıkları takdirde, metot başlığında ilan edilmeleri zorunludur.
FileNotFoundException
ayrıksı durumunun ortaya çıkması olasılığının belirmesiyle derleyici bizim kotarmak ya da bu görevi ihale etmek yönünde bir karar verdiğimizi görmek ister. Bu istemin karşılanmaması halinde ise söz konusu eksikliğe dikkat çekerek derlemenin başarısızlıkla sonlandığını bildirir. Burada bir noktanın özellikle vurgulanması yerinde olacaktır: derleyici, kodu okuyup var olmayan bir dosyanın girileceğinden emin olduğu için değil, böyle bir olasılığın var olduğu için itiraz etmektedir. Derleyicinin gözünde, FileReader
sınıfının kullanılan yapıcısı FileNotFoundException
türlü bir ayrıksı durum nesnesi fırlatabilir ve programcının da buna karşı hazırlıklı olduğunu kanıtlaması gerekir.Kotarımın sorunun çıktığı nokta yerine çağrı yığıtındaki diğer metotlara bırakıldığı metot başlığına eklenen
throws
bildirimi ile ilan edilir. Buna bir örnek aşağıda verilmiştir: m3
'te ortaya çıkabilecek sorun öngörülmüş fakat metot içinde çözülmektense metot başlığında belirtilmek suretiyle çağrı yığıtındaki diğer metotlara bırakılmıştır. Daha kesin ifade edecek olursak, m3
'te ortaya çıkabilecek sorun için top önce m2
'ye ve oradan da m1
'e atılmış ve hal çaresi bu metot içinde sağlanmıştır.
... import java.io.FileNotFoundException; public class Örnek { public static void main(String[] ksa) { // ... m1(); // ... } // void main(String[]) sonu private static void m1() { // ... try { m2(); } catch(FileNotFoundException a) { ... } // ... } // void m1() sonu private static void m2() throws FileNotFoundException { ... // ... m3(dosyaAdı); // ... } // void m2() sonu private static void m3(String dosyaAdı) throws FileNotFoundException { BufferedReader dosya = new BufferedReader(new FileReader(dosyaAdı)); // ... } // void m3(String) sonu } // Örnek sınıfının sonuKotarıcıların iliştirildikleri korumalı bölgeye özel oldukları unutulmamalıdır. Bundan dolayı, aşağıdaki kod parçası derleyici tarafından kabul görmeyecektir; kotarıcı
m2
metodunun sadece birinci kullanımına çözüm sağlamaktadır.
private static void m1() { // ... try { m2(); } catch(FileNotFoundException a) { ... } // ... m2(); // ⇒ Derleme hatası! // ... } // void m1() sonuBu noktada, neden iki kategori olduğunu soruyor olabilirsiniz. Aşağıdaki örnekle anlamaya çalışalım. Belli ki, bu basit programı yazan arkadaş Java'da dizilerin 0-temelli indislere sahip olduğunu unutmuş ve üç elemanlı bir
int
dizisi yarattıktan sonra üçüncü eleman yerine 3 indisiyle gösterilen elemanın değerini 4 olarak güncellemek istemiş. Yani, Java programlama bilgisi eksik olan arkadaş derleme zamanında yakalanamayan bir hata yapmış. Takdir edersiniz ki, böylesine bir hatanın kotarıcıda düzeltilmesi ve programa devam edilmesi olanaklı değildir. Yapılması gereken, programcı arkadaşımızın dizileri daha iyi öğrenmesi ve kullanıcıdan 0..2 aralığında değer istemesi gerektiğini farketmesidir. Çünkü, ayrıksı durum düzeneği programın beklenmedik durumlarda daha sağlıklı bir tepki vermesini sağlamak için kullanılır, kötü programcıların programlama hatalarını düzeltmesi gibi erişilmesi olanaksız bir amaç için değil.
import java.util.Scanner; public class DiziKullanımı { public static void main(String[] ksa) { int[] iDz = {1, 2, 3}; Scanner grdKanalı = new Scanner(System.in); System.out.print("1..3 aralığında bir sayı giriniz: "); iDz[grdKanalı.nextInt()] = 4; } // void main(String[]) sonu } // DiziKullanımı sınıfının sonu
$ javac -encoding UTF-8 DiziKullanımı.java $ java DiziKullanımı 1..3 aralığında bir sayı giriniz: 3 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 at DiziKullanımı.main(DiziKullanımı.java:8)Benzer bir gözlem
null
değerli bir tutacak yoluyla ileti gönderilmeye çalışılması sonrasında ortaya çıkan NullPointerException
için de yapılabilir. Sıkça kendini gösteren bu ayrıksı durumun da sebebi programlama hatasıdır ve kotarılması olanaksızdır. Dolayısıyla, yakalanması veya metot başlığında ilan edilmesi pek anlamlı olmayacaktır.3 Buna karşılık, bir dosyanın olmaması kullanıcının dosya adını giren kullanıcının dikkatsizliğinden kaynaklanabilir. Doğal olarak, bu beklenmedik durumun öngörülerek kotarıcıda ikinci bir hak verilerek programın boş yere sona ermesinin önüne geçilmelidir.Peki, ya sizin ve kullanıcının iradesi dışında gelişen sebepler nedeniyle programınız göçecek olursa. Mesela, arkadaşınız ortaklaşa kullandığınız bilgisayardan programınızın çalışması için gerekli olan bir sınıf dosyasını silecek olursa, ne olur? Ya da, dosyanın diskte kaydedildiği sektörlerden birinin bozulması nedeniyle sınıf dosyasının okunarak içselleştirilmesi söz konusu olamazsa, ne olur? Ya da ya da, programınızın işlemesi için gereksinilen kaynaklar JSM tarafından sağlanamayacak kadar büyük olmaya başlarsa, ne olur? Gelin bu soruların yanıtını
Faktöryel
sınıfını ikinci komut satırı argümanı çok büyük bir sayı ile deneyerek birlikte görelim.
$ java Faktöryel 5 5827 2> StackOverflowError.txt 5!: 120 ✔Standart hata ortamını yönlendirerek hata mesajlarını StackOverflowError.txt dosyasına gönderen yukarıdaki komutun ürettiği bilgi incelendiğinde,
fakt2
'nin sürekli kendini çağırdığı ve programın StackOverflowError
ile sonlandığı görülecektir. Yani, JSM özyinelemeli çağrılar sonucu genişleyen çağrı yığıtını doldurmuş ve taşmanın vuku bulduğu noktada imdat çağrısını yapmıştır. Bu hatanın ortaya çıkışı, JSM'nin yararlandığı yığıt büyüklüğünü -Xss512k veya -Xss1m gibi bir opsiyonla büyüterek ertelenebilir. Ancak; işin özünde çaresiz olan JSM'dir ve belleğin bittiği yerde o da bir şey yapamayacaktır. Bir diğer deyişle, beklenmedik durum dış kaynaklıdır ve programcının yapacağı fazla bir şey yoktur. Örneğimizde, özyinelemeli çözümü for
döngülüsüyle değiştirerek belki bir şeyler yapabiliriz ama bu her zaman mümkün olmayacaktır. İş böyle olunca, kotarımdan söz etmek de mantıksızdır.Bu ana kadarki bilgilerimizi maddeleyerek özetleyecek olursak aşağıdaki listeyi elde ederiz. Java programları, iç ve dış koşullara göre beklenenden farklı bir şekilde davranabilir. Davranış sapması programcının müdahele edemeyeceği dış kaynaklardan ötürüyse, programcı
Error
köklü sıradüzenindeki sınıflardan birisinin nesnesi ile haberdar edilir. Yok eğer oluşan durum içselse ve programcı tarafından çözüm bulunabilecek gibi gözüküyorsa, programcının ihtiyacının duyduğu bilgi RuntimeException
köklü sıradüzenindeki sınıflardan birisinin nesnesi ile sağlanır. Aksi takdirde, programcının yaptığı mantıksal bir hata dönüşerek ayrıksı durum haline gelmiştir ve bu, programcının dersini tamamlaması için, Exception
köklü sıradüzenindeki diğer sınıfların nesneleri ile haber verilmelidir.Throwable
: Hata ve ayrıksı durumlarError
: JSM'nin göçmesine neden olan hatalarException
: Ayrıksı durumlarRuntimeException
ve altsınıfları: Kotarılması zorunlu olmayanlar- Kotarılması zorunlu olanlar
Hangi kategoriye giriyor olursa olsun, programcı tüm koşullar altında elinden gelenin en iyisini sergilemelidir. Mümkünse, kotarıcıdaki kod ile programın sağlıklı bir şekilde devamı sağlanmalı, bu mümkün olmuyorsa, nasıl olsa bir şey yapamıyorum, denilerek oturmaktansa programın zarif bir şekilde bitmesi için elden gelen yapılmalıdır. Mesela, kullanılmakta olan dış kaynaklar kotarıcıda döndürülmeli, programın bakıcısının muhtemel bir programlama hatasını bulmasını kolaylaştırmak adına bir seyir defterine neden ile ilgili bilgiler not düşülmelidir. Bu noktada karşımıza, ayrıksı durum oluşsa da oluşmasa da çalıştırılacak kodu içeren bir kotarıcı olarak
finally
çıkıyor. Bir örnek ile görelim.
public void m() { ... try { FileReader dosya = new FileReader(...); ... } catch (java.io.IOException a) { ... } catch (ADurumu a) { return; } ... catch (Exception a) { ... } finally { dosya.close(); ... } ... } // void m() sonuBirden çok kotarıcıya sahip yukarıdaki kod parçasında,
try
bloğunun işlenmesi sırasında oluşacak duruma göre farklı kotarıcılar devreye girebilir ya da işler yolunda giderse denetim akışı finally
sonrasındaki komutla devam eder. Ancak, ne olursa olsun, finally
kotarıcısı herhalükâda işlenecektir. Bu, başka hiçbir şey yapmadan çağırıcıya dönen ADurumu
ayrıksı durumu için de geçerlidir; çünkü metottan dönüş öncesinde işlenmemiş finally
kotarıcıları sırayla işlenir. Dolayısıyla, ortaya çıkan ayrıksı durum nedeniyle işlenen kotarıcıda metottan dönülse bile kapatılamamış olan dosya muhakkak kapatılacaktır.Kod parçasında dikkat çekilmesi gereken bir diğer nokta, kotarıcıların yerleştiriliş sırasının önemli olduğudur. Bir kotarıcı sadece argümanındaki sınıfa ait nesneleri değil, o sınıfın kökü olduğu sıradüzeni içindeki tüm sınıfların nesnelerini yakalar. Örneğin, yukarıdaki ilk kotarıcı
IOException
nesnelerini yakaladığı gibi, FileNotFoundException
'ın da içinde bulunduğu pek çok sayıda sınıfın nesnelerini de yakalayacaktır. Benzer şekilde, Exception
argümanlı kotarıcı, kendisinden önce geçen kotarıcılarda yakalanmayan tüm ayrıksı durum nesnelerini yakalayarak amansız—bir o kadar da anlamsız—bir gümrük memuru görevini görecektir. Böylesine bir kotarıcının başa konulması—genelde, bir üstsınıf türlü argümana sahip kotarıcının altsınıf türlü argümana sahip kotarıcıdan önce gelmesi—her şeyi yakaladığı için takip eden kotarıcıları anlamsız kılacaktır. Kotarıcıların, özelden genele olacak şekilde sıralanması gerekir.Evet, geldik kendi ayrıksı durumunu kendin pişirmeye. Ama, yazımızın vardığı uzunluğu ve muhtemel konsantrasyon azalmasını düşünerek bunu bir başka yazıya bırakalım. Onun için, şimdilik bu kadar. Unutmayın, hatasız program(cı) olmaz; birazcık defansif programlama ortaya çıkabilecek zararın faturasını azaltır. Onun için sadece doğruluk değil, dayanıklılığa da önem verin. Yani, güvenilir yazılım üretin.
- Yazılımın benzetimi yapılan sürecin geliştiriciler (alan uzmanı, gereksinim toplayıcı, mimar, tasarımcı ve gerçekleştirimci) tarafından yorumlanması ile ortaya çıktığı unutulumamalıdır. Dolayısıyla, doğruluk özelliğini sürecin algılanışına göre yapmak daha doğru olur. ↑
- Standart hata ortamı, bir programın işleyişi sırasında üretilen hata mesajlarının gönderildiği aygıttır ve yeniden yönlendirme yapılmadığı veya
System.setErr
metodu kullanılarak değiştirilmediği müddetçe standart çıktının da gönderildiği varsayılan aygıt olan ekrandır. ↑ - Yapılan ayrımın bir diğer olumlu yanı, programların fazladan
try
-catch
yapıları vethrows
bildirimleri ile doldurulmamasıdır. Örnek olarak verdiğimiz iki ayrıksı durum düşünüldüğünde—tüm dizi erişimi ve ileti gönderimlerinintry
-catch
yapısı içine alındığını veya bu işlemleri içeren metotların imzasına ayrıksı durum ilanının eklendiğini düşünün—kotarımın zorunlu olmamasının kaynak kodun okunabilirliğine yaptığı katkı takdir edilecektir. ↑