Try catch blokları iyi kullanmak?


15

Kendimi her zaman bununla güreşiyorum ... denemek / yakalamak ve kod bu müstehcen karışıklık sekmeler, parantezler ve sıcak patates gibi çağrı yığınına geri atılan istisnalar haline değil doğru dengeyi bulmaya çalışıyorum. Örneğin, şu anda geliştirdiğim SQLite kullanan bir uygulamam var. Ben SQLite çağrıları ve Veritabanı içine / dışına gitmek için şeyler kabul eden bir Model soyutlayan bir Veritabanı arayüzü var ... Yani / eğer bir SQLite istisna oluşursa, Model (kim onu ​​çağırdı kadar) atmak zorunda ), bunu AddRecord / DeleteRecord / adlı birisine iletmek zorunda olan ...  

Hata kodları göz ardı edilebilir, unutulabilir, vb.Gibi hata kodlarını döndürmenin aksine bir istisna hayranıyım, oysa bir İstisna esasen ele alınmalıdır (verilmiş, hemen yakalayabilir ve devam edebilirim ...) eminim şu anda olanlardan daha iyi bir yol olmalı.

Düzenleme:  Ben bu biraz farklı ifadeler gerekirdi. Farklı türler olarak yeniden atmayı anlıyorum ve böyle, kötü bir şekilde ifade ettim ve bu benim kendi hatam. Benim sorum ... bunu yaparken kodu en iyi nasıl temiz tutar? Bir süre sonra bana aşırı derecede dağınık hissetmeye başlar.


Hangi programlama dili?
Apalala

2
C # şu anda, ama genel olarak düşünmeye çalışıyorum.
Mart'ta trycatch

C # atılan istisnaların bildirimini zorlamaz, bu da istisnaların makul olduğu durumlarda ele alınmasını kolaylaştırır ve programcıların gerçekte onları kullanmadan onları yakalamaya cazip gelmesini önler. C # tasarımcısı Anders Hejlsberg, bu makaledeki kontrol edilen istisnalara karşı davayı ortaya koyuyor artima.com/intv/handcuffs.html
Apalala 31:11

Yanıtlar:


14

Eğer bir kuvvetle yazılan bir dil kullanmıyor olsanız bile, güçlü yazarak açısından düşünün - yönteminiz varsa edemez , bu bir istisna atma gerektiğini bunu bekleniyor türünü döndürür.

Ayrıca, SQLException'ı modele (veya daha kötüsü, UI) sonuna kadar atmak yerine, her bir katman bilinen istisnaları yakalamalı ve bunları bu katmana uygun istisnalarla sarmalı / değiştirmeli / değiştirmelidir:

Layer      Handles Exception
----------------------------
UI         DataNotFoundException
Model      DatabaseRetrievalException
DAO        SQLException

Bu, her katmanda aradığınız istisna sayısını sınırlamanıza ve düzenli bir istisna sistemini korumanıza yardımcı olmalıdır.


Birkaç düzenleme yaptım, orijinal Q'yu kötü bir şekilde ifade ettim ... Sorumum, tüm deneme ve yakalama işlemlerini gerçekleştirirken kodun nasıl temiz tutulacağı hakkında daha fazla şey. Try catch blokları her yerde olduğunda çok dağınık hissetmeye başlar ...
trycatch

1
@Ed kullanıcı arayüzünüzün veya Modelinizin "SQLException" ı yakalaması sizi rahatsız etmiyor mu? Benim için bu pek alakalı değil. Her biri için, sanırım.
Nicole

1
@Ed, istisnaları kontrol etmeyen dillerde bir çeşit Tamam olabilir, ancak istisnaları kontrol edilmiş dillerde throws SQLExceptionSQL'in bile dahil olduğunu ima etmeyen bir yönteme sahip olmak gerçekten çirkin . Bazı işlemlerin bir dosya deposuna gitmesi gerektiğine karar verirseniz ne olur? Şimdi beyan etmelisin throws SQLException, IOException, vb. Bu kontrolden çıkacak.
Mike Daniels

1
@ Son kullanıcıya SQLException çok fazla bir şey ifade etmiyor, özellikle de sisteminiz ilişkisel veritabanları dışında birden fazla kalıcılık türünü destekliyorsa. Bir gui programcısı olarak, bir dizi düşük seviye istisnadan ziyade DataNotFoundException ile uğraşmak zorunda kalırım. Çoğu zaman düşük seviyeli bir kütüphaneye istisna, yukarıdaki normal yaşamın sadece bir parçasıdır, bu durumda soyutlama seviyeleri uygulamanınkiyle eşleştiğinde daha kolay işlenirler.
Newtopian

1
@Newtopian - Son kullanıcıya ham İstisna sunmayı asla söylemedim. Son kullanıcılar için, Destek'in toplanması için yararlı bir yerde İstisna günlüğü kaydedilirken basit bir 'Program çalışmayı durdurdu' mesajı yeterlidir. Hata Ayıklama modunda, Kural Dışı Durum'u görüntülemek yararlıdır. Bu tür İstisnalar için belirli bir işleyiciniz olmadığı sürece bir API'nın atabileceği tüm olası İstisnaları önemsememelisiniz; Un-handled Exception catcher'ınızın hepsini halletmesine izin verin.
Ed James

9

İstisnalar daha temiz kod yazılmasına izin verir, çünkü çoğunluğu normal durumla ilgilenir ve istisnai durumlar daha sonra farklı bir bağlamda bile ele alınabilir.

İstisnaları ele alma (yakalama) kuralı, aslında bu konuda bir şeyler yapabilen bağlamla yapılması gerektiğidir. Ama bunun bir istisnası var:

İstisnalar, modül sınırlarında (özellikle katman sınırları) ve sadece onları çevrelese bile, arayan için anlam taşıyan daha yüksek seviyeli bir istisna atmalıdır. Her modül ve katman, istisnalar dışında bile uygulama ayrıntılarını gizlemelidir (bir yığın modülü HeapFull atabilir, ancak asla ArrayIndexOutOfBounds'u atamaz).

Örneğinizde, üst katmanların bir SQLite istisnası hakkında herhangi bir şey yapması pek olası değildir (eğer öyleyse, hepsi SQLite ile eşleştirilir ve veri katmanını başka bir şeye değiştiremezsiniz). Ekle / Sil / Güncelle gibi şeylerin başarısız olmasının birkaç nedeni vardır ve bunların (eşzamanlı işlemlerde uyumsuz değişiklikler) veri / kalıcılık katmanında bile (bütünlük kurallarının ihlali, fi) kurtarılması imkansızdır. Kalıcılık katmanı, istisnaları model katmanı terimlerinde anlamlı bir şeye çevirmelidir, böylece üst katmanlar yeniden denenecek veya zarif bir şekilde başarısız olup olmayacağına karar verebilir.


Katılıyorum ve sorumu kötü ifade ettiğim yeri yansıtacak şekilde düzenledim. Bunun daha çok denemeyi ve yakalamayı bir şeylerden nasıl uzak tutacağımızla ilgili bir soru olması demek istedim.
Mart'ta trycatch

Bir katman veya modül içinde @Ed James ve ben bahsettiğimiz ilkeleri uygulayabilirsiniz . SQLite'ı doğrudan her yerden çağırmak yerine, SQLite ile konuşan ve istisnalardan kurtulan veya daha genel olanlara çeviren birkaç yöntem / işleve sahip olun. Bir işlem birkaç sorgu ve güncelleştirme içeriyorsa, her bir olası istisnayı işlemeniz gerekmez: tek bir dış deneme yakalama istisnaları çevirebilir ve bir iç geri alma ile kısmi güncellemelerle ilgilenebilir. Daha basit istisna işlemleri için güncellemeleri kendi işlevlerine de taşıyabilirsiniz.
Apalala

1
bu şeyler kod örnekleri ile daha kolay anlaşılır ..
Upvote 31.03.2011

Bu muhtemelen başlangıçtan itibaren yığın akışı için daha uygun bir soruydu.
Apalala

5

Genel bir kural olarak, yalnızca belirli İstisnaları (örn. IOException) ve yalnızca İstisna'yı yakaladıktan sonra yapacak belirli bir şeyiniz varsa yakalamanız gerekir.

Aksi takdirde, istisnaların yüzeye çıkmasına izin vermek en iyisidir, böylece maruz kalmaları ve bunlarla başa çıkılabilirler. Bazı insanlar buna başarısızlık derler.

Aşağıdan köpüren işlenmeyen Özel Durumları yakalamak için uygulamanızın kökünde bir tür işleyiciniz olmalıdır. Bu size İstisnayı uygun bir şekilde sunma, bildirme veya yönetme şansı verir.

Özel Durumları Sarma, dağıtılmış bir sisteme bir Özel Durum atmanız gerektiğinde ve istemcinin sunucu tarafı hatası tanımına sahip olmaması durumunda yararlıdır.


İstisnaları yakalamak ve susturmak korkunç bir şeydir. Program bozulursa, bir istisna ve bir geri izleme ile çökmelidir. Sessiz bir şekilde günlüğe kaydetme ancak verileri karıştırmaya devam etmelidir.
S.Lott

1
@ S.Lott Biri istisna susturmak gerektiğini kabul ediyorum çünkü onlar can sıkıcı buluyorum ama sadece bir uygulama çökmesini biraz aşırı. İstisnaları yakalamanın ve sistemi bilinen bir durumda sıfırlamanın mümkün olduğu birçok durum vardır, bu gibi durumlarda her şeyin küresel işleyicisi oldukça yararlıdır. Bununla birlikte, sıfırlama işlemi sırayla güvenli bir şekilde ele alınamayacak bir şekilde başarısız olursa, evet, çökmesi kişinin kafasını kuma yapıştırmaktan çok daha iyidir.
Newtopian

2
yine her şey ne inşa ettiğinize bağlıdır, ancak genellikle soyutlama sızıntısı yarattıklarından onları havaya uçurmaya katılmıyorum. Bir API kullandığımda, API'nin modeline uygun istisnalar sergilediğini görmeyi tercih ederim. Ayrıca sürprizlerden nefret ediyorum, bu yüzden bir API sadece onun uygulama ile ilgili istisnanın habersiz aracılığıyla göz atmak nefret ediyorum. Bana ne olacağına dair hiçbir fikrim yoksa nasıl tepki verebilirim! Kendimi çok sık sürprizler benim app duyurulmamış benim app çökmesini önlemek için çok daha geniş yakalamak ağları kullanın bulabilirsiniz.
Newtopian

@Newtopian: "Sarma" istisnaları ve "Yeniden Yazma" soyutlamaların sızmasını azaltır. Hala uygun şekilde havaya uçuyorlar. "Bana ne geldiğine dair hiçbir fikrim yoksa nasıl tepki verebilirim! Kendimi sık sık daha geniş yakalama ağları kullandığımı görüyorum" Yapmayı bırakmanı önerdiğimiz şey bu. Her şeyi yakalamanıza gerek yok. Zamanın% 80'i, doğru olan hiçbir şey yakalamak değildir. Zamanın% 20'si anlamlı bir yanıt veriyor.
S.Lott

1
@Newtopian, sanırım normalde bir nesne tarafından atılacak ve bu nedenle sarılması gereken istisnalar ile nesnenin kodundaki hatalardan kaynaklanan ve sarılmaması gereken istisnalar arasında ayrım yapmamız gerektiğini düşünüyorum.
Winston Ewert

4

Bir yığın sınıfı yazdığınızı düşünün. Sınıfta herhangi bir istisna işleme kodu koymazsınız, sonuç olarak aşağıdaki istisnaları üretebilir.

  1. ArrayIndexError - kullanıcı boş yığından çıkmaya çalıştığında yükseltilir
  2. NullPtrException - boş bir başvuruya başvurma girişimine neden olan uygulamadaki bir hata nedeniyle yükseltildi

İstisnaları kaydırma konusunda basit bir yaklaşım, bu istisnaların her ikisini de StackError istisna sınıfında kaydırmaya karar verebilir. Ancak, bu istisnaları sarma noktasını gerçekten kaçırıyor. Bir nesne, nesnenin bozuk olduğu anlamına gelen düşük düzeyli bir istisna atarsa. Bununla birlikte, bunun kabul edilebilir olduğu bir durum vardır: nesne gerçekten kırıldığında.

İstisnaları kaydırma noktası, nesnenin normal hatalar için uygun istisnalar vermesidir. Yığın, boş bir yığından patlarken ArrayIndexError değil StackEmpty'yi yükseltmelidir. Amaç, nesne veya kod bozulursa diğer istisnaları atmaktan kaçınmak değildir .

Ne gerçekten kaçınmak istiyoruz üst düzey nesneleri geçirildiğidir düşük seviyeli istisnalar yakalıyor. Boş bir yığından patlarken ArrayIndexError hatası atan bir yığın sınıfı küçük bir sorundur. O ArrayIndexError'ı gerçekten yakalarsanız ciddi bir sorunumuz var. Düşük seviyeli hataların yayılması onları yakalamaktan çok daha az ciddi bir günahtır.

Bunu SQLException örneğinize geri getirmek için: neden SQLExceptions alıyorsunuz? Bunun bir nedeni geçersiz sorguları iletmenizdir. Ancak, veri erişim katmanınız bozuk sorgular oluşturuyorsa bozuk. DataAccessFailure istisnasında kırılganlığını yeniden sarmaya çalışmamalıdır.

Ancak, veritabanına bağlantı kaybı nedeniyle bir SQLException oluşabilir. Bu noktadaki stratejim, son savunma hattındaki istisnayı yakalamak, kullanıcıya veritabanı bağlantısının kaybedildiğini ve kapatıldığını bildirmektir. Uygulama veritabanına kayıp erişimi olduğundan, gerçekten yapılabilecek çok fazla şey yoktur.

Kodunuzun neye benzediğini bilmiyorum. Fakat kulağa tüm istisnaları daha üst düzey istisnalara çeviriyormuşsunuz gibi geliyor. Bunu sadece nispeten az sayıda durumda yapmalısınız. Daha düşük düzeydeki istisnaların çoğu kodunuzdaki hataları gösterir. Onları yakalamak ve yeniden sarmak karşı üretkendir.

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.