TL; DR
Öncül
- Hata düzeltilemediğinde çalışma zamanı istisnaları atılmalıdır: hata koddayken ve dış duruma bağlı olmadığında (bu nedenle kurtarma kodu düzeltir).
- Kod doğru olduğunda kontrol edilen istisnalar atılmalıdır, ancak dış durum beklendiği gibi olmamalıdır: ağ bağlantısı yok, dosya bulunamadı veya bozuk vb.
Sonuç
Yayılma ya da arayüz kodu, temeldeki uygulamanın açıkça olmadığı durumlarda dış duruma bağlı olduğunu varsayarsa, kontrol edilen bir istisnayı çalışma zamanı istisnası olarak yeniden yazabiliriz.
Bu bölümde, istisnalardan birinin ne zaman atılacağı konusu ele alınmaktadır. Sonuç için daha ayrıntılı bir açıklama okumak istiyorsanız bir sonraki yatay çubuğa geçebilirsiniz.
Çalışma zamanı istisnası atmak ne zaman uygundur? Kodun yanlış olduğu ve kurtarma işleminin kodu değiştirerek uygun olduğu açık olduğunda bir çalışma zamanı istisnası atarsınız.
Örneğin, aşağıdakiler için bir çalışma zamanı istisnası atmak uygun olur:
float nan = 1/0;
Bu, sıfır çalışma zamanı istisnasına göre bir bölünme atacaktır. Bu uygundur, çünkü kod hatalı.
Örneğin, yapıcının bir kısmı HashMap
:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// more irrelevant code...
}
Başlangıçtaki kapasiteyi veya yük faktörünü düzeltmek için, doğru değerlerin girildiğinden emin olmak için kodu düzenlemeniz uygundur. Diskin mevcut durumuna bağlı olarak uzaktaki bazı sunuculara bağlı değildir. bir dosya veya başka bir program. Bu yapıcı geçersiz argümanlarla çağrılıyor, çağıran kodun doğruluğuna bağlı olarak, yanlış parametrelere veya yanlış bir hataya neden olan uygunsuz akışa yol açan yanlış bir hesaplama yapılır.
Kontrol edilen bir istisna atmak ne zaman uygundur? Sorun zaman bir kontrol istisna olan kodu değiştirmeden geri kazanılabilir. Veya farklı terimlerle ifade etmek gerekirse, kod doğruyken hata durumla ilgili olduğunda işaretli bir istisna atarsınız.
Şimdi "kurtarma" kelimesi burada zor olabilir. Hedefe ulaşmak için başka bir yol bulduğunuz anlamına gelebilir: Örneğin, eğer sunucu cevap vermezse, bir sonraki sunucuyu denemelisiniz. Eğer durumunuz için bu tür bir kurtarma mümkün ise, o zaman bu harikadır, ancak kurtarma işleminin tek yolu bu değildir - kurtarma, kullanıcıya ne olduğunu açıklayan bir hata iletişim kutusu görüntülüyor olabilir ya da bu bir sunucu uygulamasıysa bu olabilir. Yöneticiye bir e-posta göndermek veya sadece hatayı uygun ve tam olarak kaydetmek.
Mrmuggles'ın cevabında bahsedilen örneği ele alalım:
public void dataAccessCode(){
try{
..some code that throws SQLException
}catch(SQLException ex){
throw new RuntimeException(ex);
}
}
Bu, kontrol edilen istisnayı ele almanın doğru yolu değildir. Bu yöntemin kapsamındaki istisnayı ele alma konusundaki yetersizlik , uygulamanın çökmesi gerektiği anlamına gelmez. Bunun yerine, bunun gibi daha yüksek bir kapsamda yayılması uygundur:
public Data dataAccessCode() throws SQLException {
// some code that communicates with the database
}
Arayan tarafından kurtarma imkanı sağlayan:
public void loadDataAndShowUi() {
try {
Data data = dataAccessCode();
showUiForData(data);
} catch(SQLException e) {
// Recover by showing an error alert dialog
showCantLoadDataErrorDialog();
}
}
Kontrol edilen istisnalar statik bir analiz aracıdır, bir programcının belirli bir çağrıda neyin yanlış gidebileceğini, uygulamayı öğrenmelerini veya bir deneme yanılma sürecinden geçmelerini gerektirmeden açıkça belirtirler. Bu, hata akışının hiçbir bölümünün göz ardı edilmemesini sağlamayı kolaylaştırır. Kontrol edilmiş bir istisnayı çalışma zamanı istisnası olarak yeniden görüntülemek, emek tasarrufu sağlayan bu statik analiz özelliğine karşı çalışıyor.
Çağıran katmanın yukarıda gösterildiği gibi daha büyük şema şemasının daha iyi bir bağlamına sahip olduğunu belirtmekte fayda var. Çağrılacak birçok neden olabilir dataAccessCode
, aramanın özel nedeni sadece arayanlar tarafından görülebilir - bu nedenle başarısızlığın ardından doğru iyileşme konusunda daha iyi bir karar verebiliyor.
Şimdi bu ayrımı netleştirdiğimize göre, kontrol edilmiş bir istisnayı çalışma zamanı istisnası olarak yeniden başlatmanın uygun olduğu durumlarda karar vermeye devam edebiliriz.
Yukarıda verilenlere göre, bir RuntimeException olarak işaretli bir istisnayı yeniden ne zaman uygun görmek gerekir? Kullanmakta olduğunuz kod dış duruma bağımlı olduğunu varsaydığında, ancak dış duruma bağlı olmadığını açıkça belirtebilirsiniz.
Aşağıdakileri göz önünde bulundur:
StringReader sr = new StringReader("{\"test\":\"test\"}");
try {
doesSomethingWithReader(sr); // calls #read, so propagates IOException
} catch (IOException e) {
throw new IllegalStateException(e);
}
Bu örnekte, kodun yayılması, IOException
çünkü API'si Reader
dış duruma erişmek için tasarlandı, ancak StringReader
uygulamanın dış duruma erişmediğini biliyoruz . Çağrıda yer alan kısımların IO'ya veya başka bir dış duruma erişmediğini kesinlikle iddia edebileceğimiz bu kapsamda, istisnaları uygulamalarımızdan habersiz (ve muhtemelen GÇ erişim kodunun atacağını varsayarak bir IOException
).
Dış devlete bağlı istisnaları kesin olarak kontrol altında tutmanın nedeni, deterministik olmadıklarıdır (mantık bağımlı istisnaların aksine, kodun bir sürümü için her zaman tahmin edilebilir şekilde çoğaltılacaktır). Örneğin, 0'a bölmeye çalışırsanız, her zaman bir istisna oluşturacaksınız. Eğer 0'a bölmezseniz, asla bir istisna üretmezsiniz ve bu istisna vakasını ele almanız gerekmez, çünkü asla gerçekleşmez. Bununla birlikte, bir dosyaya erişme durumunda, bir kez başarılı olmak, bir dahaki sefere başarılı olacağınız anlamına gelmez - kullanıcı izinleri değiştirmiş olabilir, başka bir işlem dosyayı silmiş veya değiştirmiş olabilir. Bu yüzden, her zaman bu istisnai durumla başa çıkmak zorunda kalırsınız veya muhtemelen bir hata yaşarsınız.