İstisna yayılımı: İstisnaları ne zaman yakalamalıyım?


44

MethodA, sırayla MethodC'yi çağıran bir MethodB'yi çağırır.

MethodB veya MethodC'de işlem istisnası yoktur. Ancak MethodA'da istisna kullanımı var.

MethodC'de bir istisna oluşur.

Şimdi, bu istisna, uygun şekilde işleyen Yöntem A'ya yansıyor.

Bundaki sorun ne?

Aklımda, bir noktada arayan bir kişi MetotB veya MetotC'yi yürütecek ve bu metotlarda istisnalar meydana geldiğinde, bu metotların istisnalarını ele almaktan ne kazanılacağı, esasen sadece denemek / yakalamak / nihayet bloklamaktır. onlar callee kadar kabarcık?

İstisna işlemeyle ilgili ifade veya fikir birliği, yürütmenin yalnızca bundan dolayı devam edemediği durumlarda bir istisnadır. Anladım. Fakat neden istisnayı yakalamamak yerine, zinciri sonuna kadar denemek / yakalamak için zincirleri daha fazla ilerletmiyorsunuz?

Kaynakları serbest bırakman gerektiğinde anlıyorum. Bu tamamen farklı bir konu.


46
Neden bir fikir birliğinin bir avlanma zinciri zinciri olduğunu düşünüyorsunuz?
Caleth

İyi bir IDE ve uygun bir kodlama stiliyle, bir yöntem çağrıldığında bazı istisnaların ortaya çıkabileceğini bilirsiniz. Kullan veya yayılmasına izin ver Arayanın kararıdır. Bununla bir problem görmüyorum.
Hieu Le

14
Bir yöntem istisnayı kaldıramazsa ve yalnızca yeniden deniyorsa, bunun bir kod kokusu olduğunu söyleyebilirim. Bir yöntem istisnayı idare edemiyorsa ve bir istisna atıldığında başka bir şey yapmanıza gerek kalmazsa, bir try-catchbloğa hiç gerek yoktur .
Greg Burghardt

7
"Bundaki sorun ne ?" : hiçbir şey
Ewan

5
Doğrudan yakalama (farklı türlerde istisnalar veya buna benzer herhangi bir şey sarmaz) istisnaların tüm amaçlarını yitirir. İstisna atma karmaşık bir mekanizmadır ve kasıtlı olarak yapılmıştır. Geçişli yakalamalar amaçlanan kullanım durumuysa, tek ihtiyacınız olan bir Result<T>tür (bir hesaplama sonucunu saklayan bir tür veya bir hata) uygulamak ve aksi takdirde atma işlevlerinden geri döndürmektir. Bir hatanın yığına yayılması, her dönüş değerinin okunmasını, bir hata olup olmadığını kontrol etmeyi ve eğer öyleyse bir hata döndürmeyi gerektirir.
Alexander,

Yanıtlar:


139

Genel bir prensip olarak, onlarla ne yapacağınızı bilmiyorsanız istisnalar yakalamayın. MetodC bir istisna atarsa, ancak MetodB'nin bununla başa çıkması için yararlı bir yolu yoksa, istisnanın Metot A'ya yayılmasına izin vermelidir.

Bir yöntemin yakalama ve yeniden başlatma mekanizmasının olması için tek nedenler şunlardır:

  • Bir istisnayı, yukarıdaki arayan için daha anlamlı olan farklı bir duruma dönüştürmek istiyorsunuz.
  • İstisnaya ek bilgi eklemek istiyorsunuz.
  • Biri olmadan sızdırılacak kaynakları temizlemek için bir toplama maddesine ihtiyacınız var.

Aksi takdirde, istisnaları yanlış seviyede yakalamak, çağıran koda (ve nihayetinde yazılımın kullanıcısına) herhangi bir geri bildirim vermeden sessizce başarısız olan bir kodla sonuçlanma eğilimindedir. Bir istisna yakalamanın ve ardından hemen yeniden incelemenin alternatifi anlamsızdır.


28
@GregBurghardt, eğer dilinizde buna benzer bir şey varsa try ... finally ..., onu kullanın, yakalayın ve tekrar deneyin
Caleth

19
"Bir istisna yakalamak ve sonra hemen yeniden düşünmek anlamsızdır" Dile ve bunun nasıl yürüdüğüne bağlı olarak kod tabanına aktif olarak zarar verebilir. Çoğu zaman bu girişimde bulunanlar, orijinal yığın izleme gibi istisnalar hakkında birçok bilgiyi kaldırır. Arayan kişinin ne olduğu ve nerede olduğu konusunda tamamen yanıltıcı olan bir istisna elde ettiği kodlarla uğraştım.
JimmyJames

7
"onlarla ne yapacağını bilmiyorsan istisnaları yakalama". İlk bakışta mantıklı geliyor, ancak daha sonra sorunlara neden oluyor. Burada yaptığınız şey, arayanlara uygulama detaylarını sızdırıyor. Verileri yüklemek için uygulamanızda belirli bir ORM kullandığınızı hayal edin. Bu ORM'nin özel istisnalarını yakalamazsanız, ancak bunların kabarmasına izin vermezseniz, veri katmanınızı mevcut kullanıcılarla uyumluluğu bozmadan değiştiremezsiniz. Bu daha belirgin vakalardan biri, ancak oldukça sinsi olabiliyor ve yakalanması zor.
Voo

11
@Voo Örnekte bununla ne yapacağınızı biliyorsunuz. Örneğin, kodunuza özgü belgeli bir istisnaya sarın, örneğin LoadDataExceptionve dil özelliklerine göre orijinal istisna ayrıntılarını ekleyin, böylece gelecekteki bakımcılar kök nedeni bir hata ayıklayıcı eklemek zorunda kalmadan ve sorunun nasıl yeniden oluşturulacağını çözmeden görebilirler.
Colin Young,

14
@Voo "Bir istisnayı, yukarıdaki arayan için daha anlamlı olan farklı olana dönüştürmek istiyorsun" nedenini yakalama / yeniden inceleme senaryoları için kaçırmış gibisin.
jpmc26

21

Bundaki sorun ne ?

Kesinlikle hiçbir şey.

Şimdi, bu istisna, uygun şekilde işleyen Yöntem A'ya yansıyor.

"uygun şekilde ele alır" önemli kısımdır. Yapılandırılmış İstisna İşleme'nin temel noktası budur.

Kodunuz bir İstisna ile "yararlı" bir şey yapabilirse, bunun için gidin. Değilse, o zaman rahat bırak.

. . . neden istisnayı yakalamamaya çalışıyorum, zincirleri tamamen denemek / yakalamak için bloklar yerine zinciri daha fazla.

Yapman gereken de tam olarak buydu . Eğer işleyiciyi / yeniden okuyucuyu "tamamen aşağı" olan bir kod okuyorsanız, o zaman muhtemelen oldukça zayıf bir kod okuyorsunuzdur.

Ne yazık ki, bazı Geliştiriciler catch bloklarını yalnızca yazdıkları her yönteme attıkları (punto amaçlı değil) yazdıkları "kazan plakası" kodu olarak görürler, çünkü çoğu zaman "gerçekten" almazlar. Bu İstisnalar "kaçmaz" ve programlarını öldürmez.

Buradaki zorluğun bir kısmı, çoğu zaman bu sorunun farkına bile varılmamasıdır, çünkü İstisnalar her zaman atılmamaktadır , ancak bunlar olduğunda , program çok fazla zaman harcar ve İstisna ile gerçekten yararlı bir şeyler yapan bir yere ulaşmak için çağrı yığınını yavaş yavaş açmak için çaba gösterme.


7
Daha da kötüsü, uygulamanın istisnayı yakalaması ve ardından günlüğe kaydetmesi (umarım sadece sonsuza dek orada oturmayacağı) ve her zamanki gibi devam etmeyi denemesi, gerçekten yapamadığı zamandır.
Solomon Ucko

1
@SolomonUcko: Bu, duruma göre değişir. Örneğin, basit bir RPC sunucusu yazıyorsanız ve işlenmeyen bir istisna ana olay döngüsüne kadar tamamen kabarcıklanıyorsa, tek makul seçeneğiniz günlüğe kaydetmek, uzak eşe bir RPC hatası göndermek ve olayları devam ettirmektir. Diğer bir alternatif ise, sunucu üretimde öldüğü zaman SRE'lerinizi kurtaracak olan tüm programı öldürmektir.
Kevin

@Kevin Bu durumda, catchhatayı günlüğe kaydeden ve bir hata yanıtı döndüren mümkün olan en yüksek düzeyde bir tane olmalıdır . Her catchyere serpilmiş bloklar değil . Muhtemel kontrol edilen her istisnayı (Java gibi dillerde) listelemek istemiyorsanız, RuntimeExceptiononu oraya giriş yapmak, devam etmek ve daha fazla hataya, hatta güvenlik açığına maruz kalmak yerine sarın .
Solomon Ucko

8

Kütüphaneler ve Uygulamalar arasında bir fark yaratmalısınız.

Kütüphaneler yakalanmamış istisnaları özgürce atabilir

Bir kütüphane tasarlarken, bir noktada neyin yanlış gidebileceğini düşünmeniz gerekir. Parametreler yanlış aralıkta olabilir veya nullharici kaynaklar kullanılamayabilir vs.

Kütüphaneniz en sık onlarla mantıklı bir şekilde başa çıkmak için bir yolu olmayacak . Mantıklı olan tek çözüm uygun bir İstisna atmak ve Uygulamanın geliştiricisinin onunla ilgilenmesine izin vermektir.

Uygulamalar her zaman bir noktada istisnalar yakalamalıdır

Bir İstisna yakalandığında, onları Hatalar veya Ölümcül Hatalar olarak sınıflandırmayı seviyorum . Düzenli bir Hata , Uygulamamdaki tek bir işlemin başarısız olduğu anlamına gelir. Örneğin, hedef yazılabilir olmadığı için açık bir belge kaydedilemedi. Uygulamanın yapması gereken tek mantıklı düşünce, kullanıcıyı işlemin başarıyla tamamlanamayacağı konusunda bilgilendirmek, sorunla ilgili insan tarafından okunabilir bilgiler vermek ve sonra kullanıcının ne yapması gerektiğine karar vermesine izin vermektir.

Bir Önemli Hata ana Uygulama mantığı kurtarmak değil bir hatadır. Örneğin, grafik aygıt sürücüsü bir video oyunda çöküyorsa, Uygulamanın kullanıcıyı "nezaketle" bilgilendirmesi mümkün değildir. Bu durumda, bir günlük dosyası yazılmalı ve mümkünse kullanıcı bir şekilde veya başka bir şekilde bilgilendirilmelidir.

Bu kadar ağır bir durumda bile, Başvuru bu İstisna'yı anlamlı bir şekilde ele almalıdır. Bu, bir Günlük dosyası yazmayı, Kilitlenme Raporu göndermeyi vb. İçerebilir. Uygulamanın İstisna'ya bir şekilde yanıt vermemesi için hiçbir sebep yoktur.


Aslında, disk yazma işlemleri veya başka bir donanım manipülasyonu gibi bir şey için bir kütüphaneniz varsa, beklenmedik her türlü olayla sonuçlanabilir. Yazma sırasında bir sabit disk çıkarsa ne olur? Bir CD sürücüsü okurken kısa devre yapar? En kontrolünüz dışında ve süre o olabilir bir şey yapmak (örneğin, işlemin başarılı taklit), genellikle kütüphane kullanıcıya bir istisna ve onları karar versin için iyi bir uygulamadır. Belki bir HDDPluggedOutDuringWritingExceptionbaşa çıkılabilir ve başvuru için ölümcül değildir. Program bununla ne yapacağına karar verebilir.
VLAZ

1
@VLAZ Ölümcül ve ölümcül olmayan, uygulamanın karar vermesi gereken bir şeydir. Kütüphane ne olduğunu anlatmalı. Uygulama buna nasıl tepki vereceğine karar vermek zorundadır.
MechMK1

0

Tarif ettiğiniz modelde yanlış olan, A yönteminin üç senaryo arasında ayrım yapmanın bir yolu olmayacağıdır:

  1. B Yöntemi beklenen şekilde başarısız oldu.

  2. C Yöntemi, B Yöntemi tarafından beklenmeyen bir şekilde başarısız oldu, ancak B Yöntemi güvenli bir şekilde terk edilebilecek bir işlemi gerçekleştirirken başarısız oldu.

  3. C Yöntemi, B Yöntemi tarafından beklenmeyen bir şekilde başarısız oldu, ancak B usulü, işleri B'nin C'nin başarısızlığı nedeniyle temizleyemediği geçici bir tutarsız duruma getirmeyen bir işlem gerçekleştirirken gerçekleştirdi.

A yönteminin bu senaryoları ayırt edebilmesi için tek yol, B'den atılan istisna, bu amaç için yeterli bilgi içeriyorsa ya da B yöntemi için serbest bırakılan yığın, nesnenin açıkça geçersiz kılınmış bir durumda kalmasına neden oluyorsa olacaktır . Ne yazık ki, istisna çerçevelerin çoğu her iki modeli de zorlaştırmakta, programcıları "daha az kötü" tasarım kararları almaya zorlamaktadır.


2
Senaryo 2 ve 3, B yöntemindeki hatalardır. Yöntem A bunları düzeltmeye çalışmamalıdır.
Sjoerd,

@Sjoerd: B yönteminin, C yönteminin başarısız olabileceği tüm yolları öngörmesi nasıl öngörülür?
supercat

Temp değişkenlerine atılabilecek tüm işlemleri yapmak gibi iyi bilinen kalıplarla, daha sonra atlayamayacağınız işlemlerle - örneğin değiş tokuş etmek - eskiyi yeni durumla değiştirmek. Başka bir düzen güvenli bir şekilde tekrarlanabilecek işlemleri tanımlamaktır, bu yüzden işlemi berbat etmekten korkmadan işlemi yeniden deneyebilirsiniz. 'İstisna güvenli kodu' yazmakla ilgili tam kitaplar var, bu yüzden size burada her şeyi söyleyemem.
Sjoerd

Bu, istisnalar kullanmamak için iyi bir nokta (ki bu da mükemmel bir karar olurdu). Ancak sanırım OP, istisnaları ilk etapta kullanmak niyetinde göründüğü için, soruyu gerçekten cevaplamıyor ve sadece avın nerede olması gerektiğini soruyor .
cmaster

@Sjoerd Metod B, istisnalar dilin yasaklanıp yasaklanmadığı konusunda aklınıza gelmesi çok daha kolay hale gelir. Çünkü bu durumda, B'deki tüm kontrol akış yollarını görüyorsunuz ve hangi operatörlerin atma biçiminde (C ++) aşırı yüklenebileceğini tahmin etmek zorunda değilsiniz. Senaryo 3'ten kaçınıyoruz. "Sadece" istisnalar atarak hataların iadesi konusunda tembel olmak için açıklık ve güvenlik. Çünkü, sonunda, hata işleme olan kodun önemli bir parçasıdır.
cmaster
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.