Ne zaman istisna atmalı?


435

Uygulamamın beklemediği her koşul için oluşturulmuş istisnalar var. UserNameNotValidException, PasswordNotCorrectExceptionVb

Ancak bana bu koşullar için istisnalar oluşturmamam gerektiği söylendi. Benim UML'mde bunlar ana akış için istisnalar, öyleyse neden istisna olmasın?

İstisna oluşturmak için herhangi bir rehberlik veya en iyi uygulama var mı?


58
Lütfen tekrar açın, bu çok mantıklı ve geçerli bir soru. Herhangi bir soru belirli bir görüş içerir, ancak bu durumda bunun 'en iyi uygulama' meselesi olduğundan şüpheleniyorum.
Tim Long

19
Yeniden açmak için +1. Diğer birçok ilginç konu 'bağımlıdır' ve karar verirken ödünleşmeleri analiz etmek çok yararlıdır. İnsanların fikirleri cevaplardaki gerçeklerle karıştırması, bunu reddetmez. Çamurdan elemek okuyucuya bırakılması gereken bir egzersizdir.
aron

12
Ayrıca en iyi uygulamalarla ilgili olduğu için bu sorunun yeniden açılması gerektiğine katılıyorum. Bu arada en iyi uygulamalar her zaman başkalarına yardımcı olabilecek görüşlerdir.
Ajay Sharma

6
Microsoft şöyle diyor: "Hata kodlarını döndürmeyin. İstisnalar, çerçevelerdeki hataları bildirmenin birincil yoludur." ve "... Eğer bir üye yapmak için tasarlandığını başarılı bir şekilde yapamazsa, bu bir icra hatası olarak görülmeli ve bir istisna atılmalıdır.". msdn.microsoft.com/library/ms229030%28v=vs.100%29.aspx
Matsen75

4
Bunlar tamamen mantıklı bir istisna olabilir, sadece hangi yöntemlerin onları attığına bağlıdır. IsCredentialsValid(username,password)Kullanıcı adı veya şifre geçersizse, çağrılan bir yöntem bir istisna atmamalı, ancak yanlış döndürmelidir. Ancak, kimlik doğrulaması başarısız olursa, veritabanından veri okuyan bir yöntemi meşru bir şekilde böyle bir istisna atabilir. Kısacası: Bir yöntem yapılması gereken görevi yapamıyorsa bir istisna atmalısınız.
JacquesB

Yanıtlar:


629

Kişisel kılavuzum şu şekildedir: geçerli kod bloğunun temel varsayımı yanlış olarak bulunursa bir istisna atılır.

Örnek 1: rasgele bir sınıfı incelemesi ve <> Listeden miras alırsa true döndürmesi gereken bir fonksiyonum olduğunu varsayalım. Bu işlev, "Bu nesne Listenin torunu mu?" Bu işlev hiçbir zaman bir istisna atmamalıdır, çünkü işleminde gri alanlar yoktur - her sınıf ya <> Listeden miras alır ya da almaz, bu nedenle cevap her zaman "evet" veya "hayır" dır.

Örnek 2: List <> 'i inceleyen ve uzunluğu 50'den büyükse true, uzunluğu küçükse false döndüren başka bir işlevim olduğunu varsayalım. Bu işlev, "Bu listede 50'den fazla öğe var mı?" Ancak bu soru bir varsayım yapar - verildiği nesnenin bir liste olduğunu varsayar. Eğer bir NULL verirsem, o zaman bu varsayım yanlış olur. İşlevin döndüreceği Bu durumda, ya gerçek ya da sahte, o zaman kendi kurallarını kırmak olduğunu. İşlev hiçbir şey döndüremez ve soruyu doğru yanıtladığını iddia edemez. Bu yüzden geri dönmez - bir istisna atar.

Bu, "yüklü soru" mantıksal yanlışlığı ile karşılaştırılabilir. Her fonksiyon bir soru sorar. Girilen girdi bu soruyu yanlış yaparsa, bir istisna atayın. Bu satır, boşluk döndüren işlevlerle çizmek daha zordur, ancak en alt satır: işlevin girdileriyle ilgili varsayımları ihlal edilirse, normal dönmek yerine bir istisna atmalıdır.

Bu denklemin diğer tarafı: işlevlerinizin sık sık istisnalar attığını görürseniz, muhtemelen varsayımlarını düzeltmeniz gerekir.


15
Kesinlikle! Yalnızca işlev ön koşulları (bağımsız değişkenlerle ilgili varsayımlar) bozulduğunda bir istisna atılır !
Lightman

11
Dilbilimde buna bazen varsayım hatası denir . Klasik örnek Bertrand Russell'dan kaynaklanmaktadır: "Fransa Kralı kel mi?" Evet ya da hayır olarak cevaplanamaz, (sırasıyla "Fransa Kralı keldir" ne doğru ne de yanlıştır) yani Fransa Kralı var. Ön varsayım hatası genellikle belirli tanımlarla görülür ve programlama sırasında bu yaygındır. Örneğin, "Listenin başı" liste boşken bir ön varsayım hatası verir ve ardından bir istisna atmak uygundur.
Mohan

Bu muhtemelen en iyi açıklamadır!
gaurav

Teşekkür ederim. Yani. Çok. "Fransa Kralı kel". Bunu daha önce meinong'un ormanını araştırırken duymuştum .... :) Teşekkür ederim. @Mohan
ErlichBachman

285

Çünkü bunlar normalde olacak şeyler. İstisnalar kontrol akış mekanizmaları değildir. Kullanıcılar genellikle şifreleri yanlış anlarlar, bu istisnai bir durum değildir. İstisnalar gerçekten nadir bir şey olmalı, UserHasDiedAtKeyboardtip durumlar.


3
Hmm, hayır. Çoğu web uygulaması için geçerli olan maksimum performans gerekli değilse, istisnalar kontrol akış mekanizması olarak kullanılabilir. Python, yineleyicileri sonlandırmak için 'StopIteration' istisnasını kullanır ve çok iyi çalışır. Maliyet IO, vs. ile karşılaştırıldığında hiçbir şey değildir
Seun Osewa

9
+1 mükemmel cevap. API'ler üzerinde çalışan geliştiriciler tarafından o kadar sinirliyim ki, her küçük şey için tüketmek ve İstisnalar atmak zorundayım. ÇOK az vaka gerçekten istisna gerektirir. Tanımlanmış 25 farklı istisna türünüz varsa, tasarımınıza tekrar bakın, yanlış yapıyor olabilirsiniz.
7wp

1
kullanıcı web sayfası kodunu değiştirerek izin verilmeyen yasadışı bir eylem denediğinde, örneğin StackOverflow'daki başka birinin gönderilerini silmek için bir istisna olmalı mı?
Rajat Gupta

30
İstisnalar akış mekanizmalarını kontrol eder. Onları atabilirsin. Onları yakalayabilirsiniz. Kontrolü başka bir kod parçasına taşıdınız. Bu kontrol akışı. Dillerin istisnalara sahip olmasının tek nedeni, "bu şey başarısız mı oldu?" Sorusu olmadan doğrudan kod yazabilmenizdir. yaptığınız her şeyden sonra. Örneğin Haskell'in istisnaları yoktur, çünkü monad'lar ve yapılacaklar sizin için hata denetimini otomatikleştirebilir.
Jesse

2
İstisnalar kontrol akış mekanizmalarından daha fazlasıdır. Onlar (yöntem) müşteriye onlar olmalıdır istisnai sonuçlar hakkında yararlı bilgiler vermek farkında ve ele. Yani, doğru kullanıldığında, istisnalar API'leri daha sağlam hale getirir
idelvall

67

Küçük yönergelerim "Kod tamamlandı" adlı büyük kitaptan büyük ölçüde etkileniyor:

  • Göz ardı edilmemesi gereken şeyleri bildirmek için istisnalar kullanın.
  • Hata yerel olarak ele alınabiliyorsa istisnalar kullanmayın
  • İstisnaların, rutininizin geri kalanıyla aynı soyutlama düzeyinde olduğundan emin olun.
  • İstisnalar gerçekten istisnai olanlara ayrılmalıdır .

35

Kullanıcı adı geçerli değilse veya şifre doğru değilse bir istisna DEĞİLDİR. Bunlar normal çalışma akışında beklemeniz gereken şeyler. İstisnalar, normal program işleminin bir parçası olmayan ve oldukça nadir olan şeylerdir.

EDIT: Ben istisnalar kullanmayı sevmiyorum çünkü bir yöntemin sadece çağrı bakarak bir istisna atıp atmadığını söyleyemezsiniz. Bu nedenle istisnalar yalnızca durumu iyi bir şekilde ele alamazsanız kullanılmalıdır ("bellek yetersiz" veya "bilgisayar yanıyor" düşünün).


"İstisnaları kullanmayı sevmiyorum çünkü bir yöntemin sadece çağrıya bakarak bir istisna verip vermediğini söyleyemezsiniz." Bu yüzden onları destekleyen diller için kontrol edilmiş istisnalar vardır.
Newtopian

1
Kontrol edilen istisnaların kendi sorunları vardır. Normal iş akışının parçası olan şeyler için değil, "istisnai durumlar" istisnalarını kullanmayı tercih ederim.
EricSchaefer

2
Düzenlemenize yanıt olarak. Ben xml dokümanlar her zaman özet bölümü sonunda işlevin atar istisnalar koymak böylece bilgileri intellisense görebilirsiniz.
Matthew Vines

1
kullanıcı web sayfası kodunu değiştirerek izin verilmeyen yasadışı bir eylem denediğinde, örneğin StackOverflow'daki başka birinin gönderilerini silmek için bir istisna olmalı mı?
Rajat Gupta

1
Hata işleme (hatalar, bellek, bilgisayar yanıyor) ve kod istisnaları (eksik kayıt, geçersiz giriş türü, vb.) Bence ikisi arasında belirgin bir fark var.
Chuck Burgess

28

Temel kurallardan biri, normalde tahmin edemediğiniz bir şeyde istisnalar kullanmaktır. Örnekler, veritabanı bağlantısı, diskteki eksik dosya, vb. Tahmin edebileceğiniz senaryolar için, yani kötü bir parola ile giriş yapmaya çalışan kullanıcılar, booleans döndüren ve durumun nasıl zarif bir şekilde ele alınacağını bilen işlevleri kullanmalısınız. Birisi parolasını yanlış yazdığı için bir istisna atarak yürütmeyi aniden sonlandırmak istemezsiniz.


6
bir istisnada programın yürütülmesini durdurmanıza gerek yoktur ... istisnayı atın, arayan sonra istisna yakalar ve mümkünse günlük ve hata ve devam etmelidir. Çağrı yığınına istisnalar atmaya devam etmek 'kötü bir form' - gerçekleştiği yerde yakalayın ve orada onunla başa
çıkın

2
ama eğer doğrudan halledebilirsen neden onları fırlatabilirsin. eğer şifre yanlış ya da bir şey yanlış ben sadece bir if bir yanlış dönmek ve bir hata vermek izin
My1

" diskte dosya eksik " .NET framework gibi birçok dil çerçevesi dosya varlığını da kontrol etmek için API'ler sağlar. Neden dosyaya doğrudan erişmeden önce onları kullanmıyorsunuz?
user1451111

23

Diğerleri, kullanıcı yanlış yazılırsa, normal girişte kötü giriş bekleneceği için istisnaların kullanılmaması gerektiğini önermektedir. Ben katılmıyorum ve akıl yürütmüyorum. Dosya açmayla karşılaştırın .. Dosya yoksa veya herhangi bir nedenle kullanılamıyorsa, çerçeve tarafından bir istisna atılır. Yukarıdaki mantığı kullanmak Microsoft tarafından bir hataydı. Bir hata kodu döndürmeliydiler. Ayrıştırma, web istekleri, vb.

Normal bir akışın kötü bir giriş parçası olduğunu düşünmüyorum, olağanüstü. Normalde kullanıcı doğru şifreyi yazar ve dosya mevcut olur. İstisnai durumlar istisnai bir durumdur ve bunlar için istisnalar kullanmak mükemmeldir. Dönüş değerlerini y üstündeki n seviye boyunca yayarak kodunuzu karmaşıklaştırmak enerji israfıdır ve dağınık kodla sonuçlanır. Muhtemelen işe yarayacak en basit şeyi yapın. Hata kodlarını kullanarak erken optimizasyon yapmayın, tanım gereği istisnai şeyler nadiren gerçekleşir ve istisnalar, bunları atmadıkça hiçbir maliyeti yoktur.


Bunun dışında, dosyayı açmadan önce (tabii ki çerçevenize bağlı olarak) var olup olmadığını kontrol edebilirsiniz. Böylece bu tesis var ve eğer dosya çek ile açılmaya çalışılıyor arasında kaybolursa, bu bir istisnadır.
blowdart

7
Mevcut dosya, kullanıcının örneğin dosyaya yazmasına izin verildiği anlamına gelmez. Olası her sorunun kontrol edilmesi gerçekten sıkıcı ve hataya açıktır. + kodu çoğalıyorsunuz (DRY).
Bjorn Reppen

Geçersiz parola İstisnası olan bir nokta, dönüş kodu çözümü ile karşılaştırıldığında herhangi bir yavaşlığın, bir parola yazarak insan kullanıcı için algılanamayacağıdır.
paperhorse

7
Msgstr "Dönüş değerlerini y üstündeki n seviyeden geçirerek kodunuzu karmaşıklaştırmak enerji israfıdır ve dağınık kodla sonuçlanır". Bu benim için istisnaları kullanmak için çok güçlü bir neden. İyi kod genellikle küçük fonksiyonlardan oluşur. Bu hata kodunu küçük bir işlevden diğerine tekrar tekrar iletmek istemezsiniz.
Haziran'da beluchin

Bence kafa karışıklığı, belki de bir login-tip yönteminin öngörülebilir bir sonucunun bir parolanın yanlış olabileceği, aslında bunu belirlemek için kullanılabileceği ve bu durumda bir istisna olmasını istemeyeceği varsayımından kaynaklandığını düşünüyorum ; file openbelirli bir sonucu istenen bir tür senaryosunda - sistem yanlış giriş parametreleri veya bazı harici faktörler nedeniyle sonucu veremezse, bu bir istisnanın mükemmel mantıksal kullanımıdır.
Mayıs

17

İstisnalar biraz maliyetli bir etkidir, örneğin geçersiz bir şifre sağlayan bir kullanıcınız varsa, bir hata bayrağını veya geçersiz olduğunu gösteren başka bir göstergeyi geri vermek genellikle daha iyi bir fikirdir.

Bunun nedeni, istisnaların ele alınma şekli, gerçek hatalı giriş ve benzersiz kritik durdurma öğelerinin istisnalar olması gerekir, ancak oturum açma bilgileri başarısız olmaz.


14

Sadece mevcut durumunuzdan çıkmak için yapabileceğiniz hiçbir şey olmadığında bir istisna atmanız gerektiğini düşünüyorum. Örneğin, bellek ayırıyorsanız ve tahsis edilecek bir şey yoksa. Bahsettiğiniz durumlarda, bu durumlardan açıkça kurtulabilir ve buna göre bir hata kodunu arayana geri döndürebilirsiniz.


Bu sorunun yanıtları da dahil olmak üzere, yalnızca "istisnai" durumlarda istisnalar atmanız gerektiği konusunda bolca tavsiye göreceksiniz. Bu yüzeysel olarak makul görünüyor, ancak kusurlu bir tavsiye, çünkü bir soruyu ("ne zaman bir istisna atmalıyım") başka bir öznel soru ("istisnai olan") ile değiştirir. Bunun yerine, Herb Sutter'in tavsiyelerine uyun (C ++ için, Dr Dobbs İstisnaları Ne Zaman ve Nasıl Kullanılır makalesinde ve ayrıca C ++ Kodlama Standartları Andrei Alexandrescu ile olan kitabında mevcuttur ):

  • bir ön koşul karşılanmaz (genellikle aşağıdakilerden birini imkansız kılar) veya
  • alternatif bir post-koşulu karşılayamaz veya
  • alternatif bir değişmezi sürdüremez.

Bu neden daha iyi? Soruyu ön koşullar, son koşullar ve değişmezler hakkında birkaç soru ile değiştirmiyor mu? Bağlantılı birkaç nedenden dolayı bu daha iyidir.

  • Önkoşullar, sonkoşullar ve değişmezler, programımızın (dahili API'sı) tasarım özellikleridir, oysa bu karar throwbir uygulama detayıdır. Bizi tasarım ve uygulamasını ayrı ayrı ele almamız gerektiğini ve bir yöntem uygularken işimizin tasarım kısıtlamalarını karşılayan bir şey üretmemiz gerektiğini aklımızda tutmaya zorlar.
  • Bizi, metodumuzu arayanların yapması gereken tek varsayım olan önkoşullar, sonkoşullar ve değişmezler açısından düşünmeye zorlar ve programımızın bileşenleri arasında gevşek birleşme sağlayarak tam olarak ifade edilir.
  • Bu gevşek bağlantı daha sonra gerekirse uygulamayı yeniden düzenlememizi sağlar.
  • Post-koşullar ve değişmezler test edilebilir; sonradan test edilebilen bir kodla sonuçlanır, çünkü post-koşullar, birim-test kodumuzun kontrol edebileceğini tahmin eder (iddia).
  • Post-koşullar açısından düşünmek doğal olarak post-condition olarak başarılı olan ve istisnaları kullanmanın doğal tarzı olan bir tasarım üretir . Programınızın normal ("mutlu") yürütme yolu doğrusal olarak düzenlenir ve tüm hata işleme kodu catchyan tümcelere taşınır .

10

İstisnaların ne zaman kullanılacağına dair sert ve hızlı kurallar olmadığını söyleyebilirim. Bununla birlikte, bunları kullanmanın veya kullanmamanın iyi nedenleri vardır:

İstisnaları kullanma nedenleri:

  • Genel durum için kod akışı daha net
  • Karmaşık hata bilgilerini bir nesne olarak döndürebilir (buna referansla iletilen "out" parametresi kullanılarak da ulaşılabilir)
  • Diller, kural dışı durum durumunda düzenli temizliği yönetmek için bazı olanaklar sağlar (C # 'da deneyin, / son olarak Java'da, C ++' da RAII kullanarak)
  • Herhangi bir istisna atılmaması durumunda, yürütme bazen dönüş kodlarını kontrol etmekten daha hızlı olabilir
  • Java'da, kontrol edilen istisnalar bildirilmeli veya yakalanmalıdır (buna karşı bir neden olabilir)

İstisnaları kullanmama nedenleri:

  • Hata işleme basitse bazen aşırıya kaçar
  • İstisnalar belgelenmez veya bildirilmezse, arama kodu tarafından yakalanmamış olabilirler; bu, arama kodunun bir dönüş kodunu görmezden gelmesinden daha kötü olabilir (uygulama çıkışı - sessiz hataya karşı - daha kötü olan senaryoya bağlı olabilir)
  • C ++ 'da, istisnalar kullanan kod istisna açısından güvenli olmalıdır (bunları atmasanız veya yakalamasanız da dolaylı olarak bir fırlatma işlevi çağırsanız bile)
  • C ++ 'da, bir fonksiyonun ne zaman atılabileceğini söylemek zordur, bu nedenle bunları kullanırsanız istisna güvenliği konusunda paranoyak olmalısınız
  • İstisna atma ve yakalama, bir dönüş bayrağını kontrol etmeye kıyasla genellikle çok daha pahalıdır

Genel olarak, Java'da istisnaları C ++ veya C # 'dan daha fazla kullanmaya eğilimliyim, çünkü beyan edilen veya edilmeyen bir istisnanın temelde bir fonksiyonun resmi arayüzünün bir parçası olduğu kanaatindeyim, çünkü istisna garantinizi değiştirmek çağrı kodunu kır. Bunları Java IMO'da kullanmanın en büyük avantajı, arayanın istisnayı ele alması gerektiğini bilmenizdir ve bu da doğru davranış şansını artırır.

Bu nedenle, herhangi bir dilde, her zaman ortak bir sınıftan bir kod veya API katmanındaki tüm istisnaları türetirim, böylece çağrı kodu her zaman tüm istisnaları yakalamayı garanti edebilir. Ayrıca, bir API veya kitaplık yazarken uygulamaya özgü istisna sınıfları atmak kötü olur (yani, aracınızın aldığı istisnanın arayüzünüz bağlamında anlaşılabilir olması için alt katmanlardan istisnaları sarın).

Java'nın, genel ve Çalışma Zamanı özel durumları arasında ayrım yapıldığını unutmayın; ikincisinin bildirilmesi gerekmez. Hata, programdaki bir hatanın sonucu olduğunu bildiğiniz zaman yalnızca Çalışma Zamanı özel durum sınıflarını kullanırdım.


5

İstisna sınıfları "normal" sınıflara benzer. Yeni bir sınıf, farklı alanlara ve farklı işlemlere sahip farklı bir nesne türü "olduğunda" oluşturulur.

Genel bir kural olarak, istisna sayısı ile istisnaların ayrıntı düzeyi arasındaki dengeyi denemelisiniz. Yönteminiz 4-5'ten fazla farklı istisna atarsa, muhtemelen bazılarını daha "genel" istisnalarla birleştirebilirsiniz (örneğin, durumunuzda "AuthenticationFailedException") ve neyin yanlış gittiğini detaylandırmak için istisna mesajını kullanabilirsiniz. Kodunuz her birini farklı işlemiyorsa, çok sayıda istisna sınıfı oluşturmanıza gerek yoktur. Ve eğer varsa, ortaya çıkan hatayla bir enum döndürmelisiniz. Bu şekilde biraz daha temiz.


5

Tekrar tekrar bir istisnaya neden olacak bir döngü içinde çalışan kod ise, istisnaları atmak iyi bir şey değildir, çünkü büyük N için oldukça yavaştırlar.Ancak performans yoksa özel istisnalar atmanın yanlış bir yanı yoktur. sorun. Bunların hepsinin miras aldığı, BaseException veya bunun gibi bir şeye sahip olduğunuzdan emin olun. BaseException, System.Exception öğesini devralır, ancak tüm istisnalarınız BaseException öğesini devralır. Benzer türleri gruplamak için bir İstisna türleri ağacınız bile olabilir, ancak bu aşırı olabilir veya olmayabilir.

Yani, kısa cevap, önemli bir performans cezasına neden olmazsa (çok fazla istisna atmadığınız sürece olmamalıdır), o zaman devam edin.


Bir döngü içindeki istisnalar hakkındaki yorumunuzu gerçekten beğendim ve kendim denemeyi düşündüm. Bir döngü int.MaxValuesüreleri çalıştıran ve içinde 'sıfıra bölme' istisnası üreten bir örnek program yazdım . EĞER / BAŞKA versiyonu, temettü Bölme işleminin öncesinde değil sıfır ise hangi ı kontrol ediyordu 6082 ms ve deneme / yakalama sürümü ise 15.407.722 kene, tamamlanan, ben istisna üreten ve istisna yakalamak edildiği 28174385 tamamlanan, ms ve 71371326155 keneler: if / else versiyonundan 4632 kat daha fazla.
user1451111

3

Oradaki japollock'a katılıyorum - bir operasyonun sonucundan emin değilseniz bir kabul atın. API'lara yapılan çağrılar, dosya sistemlerine erişme, veritabanı çağrıları vb. Her zaman programlama dillerinizin "sınırlarını" geçtiğinizde.

Eklemek istiyorum, standart bir istisna atmaktan çekinmeyin. "Farklı" bir şey yapmayacaksanız (görmezden gel, e-posta, günlük, twitter balina resmini göster, vb), o zaman özel istisnalarla uğraşmayın.


3

istisnalar atmanın temel kuralı oldukça basittir. kodunuz GERİ ÇIKARILMAZ GEÇERSİZ durumuna girdiğinde bunu yaparsınız. verilerin güvenliği ihlal edilirse veya o noktaya kadar gerçekleşen işlemi geri alamazsanız, sonlandırmanız gerekir. Gerçekten başka ne yapabilirsiniz? işlem mantığınız sonunda başka bir yerde başarısız olur. bir şekilde kurtarabilirseniz, bunu yapın ve istisna atmayın.

özel durumunuzda para çekme işlemini kabul etmek gibi aptalca bir şey yapmak zorunda kaldıysanız ve ancak o zaman kullanıcı / parolayı kontrol edin, kötü bir şeyin olduğunu bildirmek ve daha fazla hasarı önlemek için bir istisna atarak işlemi sonlandırmalısınız.


2

Genel olarak, uygulamanızda "Olağanüstü" olabilecek herhangi bir şey için bir istisna atmak istersiniz.

Örneğinizde, bu istisnaların her ikisi de onları bir şifre / kullanıcı adı doğrulaması yoluyla çağırdığınız gibidir. Bu durumda, bir kullanıcının bir kullanıcı adını / şifreyi yanlış yazmasının gerçekten istisnai olmadığı iddia edilebilir.

Bunlar, UML'nizin ana akışına "istisnalar" dır, ancak işlemede daha fazla "daldır".

Passwd dosyanıza veya veritabanınıza erişmeyi denediyseniz ve yapamazsanız, bu istisnai bir durumdur ve bir istisna atmayı gerektirecektir.


" Passwd dosyanıza veya veritabanınıza erişmeyi denediyseniz ve yapamıyorsanız, bu istisnai bir durumdur ve bir istisna atmayı gerektirecektir. " .NET çerçevesi gibi çoğu dil çerçevesi dosya varlığını da kontrol etmek için API'ler sağlar. Neden dosyaya doğrudan erişmeden önce onları kullanmıyorsunuz?
user1451111

2

İlk olarak, API'nızın kullanıcıları belirli, ayrıntılı hatalarla ilgilenmiyorsa, bunlar için özel istisnalara sahip olmanın herhangi bir değeri yoktur.

Kullanıcılarınız için neyin yararlı olabileceğini bilmek genellikle mümkün olmadığından, daha iyi bir yaklaşım belirli istisnalara sahip olmaktır, ancak ortak bir sınıftan miras kaldıklarından emin olmaktır (örneğin, std :: exception veya C ++'daki türevleri). Bu, müşterinizin istedikleri belirli istisnaları veya umursamadıklarında daha genel istisnaları yakalamasını sağlar.


2

İstisnalar, anormal davranışlar, hatalar, hatalar ve benzeri olaylar içindir. Fonksiyonel davranış, kullanıcı hatası vb. Program mantığı tarafından ele alınmalıdır. Kötü bir hesap veya parola bir oturum açma yordamındaki mantık akışının beklenen bir parçası olduğundan, bu durumları istisnasız halledebilmelidir.


2

İstisnaların kullanımıyla ilgili felsefi problemlerim var. Temel olarak, belirli bir senaryonun gerçekleşmesini bekliyorsunuz, ancak bunu açıkça ele almak yerine, sorunu "başka bir yerde" ele almaya itiyorsunuz. Ve bu "başka yerde" nin olduğu yerde herkes tahmin edebilir.


2

Genelde her köktenciliğin cehenneme götürdüğünü söyleyebilirim.

Kesinlikle istisna odaklı akışla sonuçlanmak istemezsiniz, ancak istisnalardan tamamen kaçınmak da kötü bir fikirdir. Her iki yaklaşım arasında bir denge bulmalısınız. Yapmayacağım her istisnai durum için bir istisna türü yaratmak. Bu verimli değil.

Genel olarak tercih ettiğim, sistem genelinde kullanılan iki temel istisna türü oluşturmaktır: LogicalException ve TechnicalException . Bunlar gerektiğinde alt tiplerle daha da ayırt edilebilir, ancak genellikle gerekli değildir.

Teknik istisna, veritabanı sunucusunun kapanması gibi gerçekten beklenmedik istisnayı gösterir, web servisine bağlantı IOException istisnasını attı vb.

Diğer yandan, mantıksal istisnalar, daha az şiddetli hatalı durumu üst katmanlara yaymak için kullanılır (genellikle bir doğrulama sonucu).

Mantıksal istisnanın bile program akışını kontrol etmek için düzenli olarak kullanılması amaçlanmadığını, aksine akışın gerçekten sona ermesi gerektiğini vurgulamak gerektiğini lütfen unutmayın. Java'da kullanıldığında, her iki istisna türü de RuntimeException alt sınıflarıdır ve hata işleme büyük ölçüde en boyuta yöneliktir.

Yani giriş örneğinde AuthenticationException gibi bir şey oluşturmak ve somut durumları UsernameNotExisting , PasswordMismatch vb. Gibi numaralandırma değerleriyle ayırt etmek akıllıca olabilir . Sonra büyük bir istisna hiyerarşisine sahip olmayacaksınız ve catch bloklarını sürdürülebilir düzeyde tutabilirsiniz. . İstisnalar kategorize edildiğinden ve kullanıcıya ne ve nasıl yayılacağını oldukça iyi bildiğinizden, bazı genel istisna işleme mekanizmalarını da kolayca kullanabilirsiniz.

Tipik kullanımımız, kullanıcının girişi geçersiz olduğunda Web Hizmeti çağrısı sırasında LogicalException özel durumunu kullanmaktır. Özel Durum, SOAPFault ayrıntısına göre sıralanır ve daha sonra istemcide özel duruma göre yeniden sıralanır; bu da, özel durumun bu alana uygun eşlemesi olduğundan belirli bir web sayfası giriş alanında doğrulama hatası gösterilmesine neden olur.

Bu kesinlikle tek durum değil: istisnayı fırlatmak için web servisine ihtiyacınız yok. İstisnai bir durumda bunu yapmakta özgürsünüz (hızlı başarısız olmanız gerektiği gibi) - hepsi sizin takdirinize bağlıdır.


2

benim için gerekli bir teknik veya iş kuralı başarısız olduğunda istisna atılmalıdır. Örneğin, bir araba varlığı 4 lastik dizisiyle ilişkilendirilmişse ... bir lastik veya daha fazlası boşsa ... "NotEnoughTiresException" özel durumunun kullanılması gerekir, çünkü sistemin farklı düzeylerinde yakalanabilir ve günlüğe kaydetme yoluyla anlam. ayrıca sadece null akış kontrol etmek ve arabanın örnekleme önlemek için çalışın eğer. Asla sorunun kaynağını bulamayabiliriz, çünkü lastiğin en başta boş olması gerekmiyordu.


1

bir istisna atmaktan kaçınmanın temel nedeni, bir istisna atmakla ilgili çok fazla ek yükün olmasıdır.

Aşağıdaki makalede belirtildiği gibi bir istisna istisnai koşullar ve hatalar için olmasıdır.

Yanlış kullanıcı adı mutlaka bir program hatası değil, bir kullanıcı hatasıdır ...

.NET'teki istisnalar için iyi bir başlangıç ​​noktası: http://msdn.microsoft.com/en-us/library/ms229030(VS.80).aspx


1

İstisnaları atmak yığının gevşemesine neden olur, bu da bazı performans etkileri vardır (kabul edilen modern yönetilen ortamlar bu konuda iyileşmiştir). Yine de iç içe geçmiş bir durumda defalarca istisnalar atmak ve yakalamak kötü bir fikir olacaktır.

Muhtemelen bundan daha önemli, istisnalar istisnai durumlar içindir. Sıradan kontrol akışı için kullanılmamalıdır, çünkü bu kodunuzun okunabilirliğine zarar verecektir.


1

Üç tip koşulum var.

  1. Hatalı veya eksik giriş bir istisna olmamalıdır. Tespit etmek, öznitelikleri ayarlamak ve iletilerle aynı sayfaya geri dönmek için hem istemci tarafı js hem de sunucu tarafı normal ifadesini kullanın.

  2. AppException. Bu genellikle kodunuzda algıladığınız ve attığınız bir istisnadır. Başka bir deyişle, bunlar beklediğiniz dosyalardır (dosya mevcut değildir). Günlüğe kaydedin, iletiyi ayarlayın ve genel hata sayfasına geri dönün. Bu sayfa genellikle ne olduğu hakkında biraz bilgi içerir.

  3. Beklenmedik İstisna. Bunlar bilmediğinizler. Ayrıntılarla günlüğe kaydedin ve genel bir hata sayfasına yönlendirin.

Bu yardımcı olur umarım


1

Güvenlik sizin örneğinizle ilgilidir: Bir saldırgana bir kullanıcı adının mevcut olduğunu söylememelisiniz, ancak şifre yanlıştır. Bu, paylaşmanız gerekmeyen ekstra bilgiler. "Kullanıcı adı veya şifre yanlış" demeniz yeterli.


1

Basit cevap, bir işlem imkansız olduğunda (her iki uygulamadan dolayı VEYA iş mantığını ihlal edeceği için). Bir yöntem çağrılırsa ve yöntemin yazmak için yapması mümkün değilse, bir İstisna atın. Bunun iyi bir örneği, sağlanan parametreler kullanılarak bir örnek oluşturulamazsa kurucuların her zaman ArgumentExceptions parametrelerini atmasıdır. Başka bir örnek, sınıfın başka bir üyesinin veya üyelerinin durumu nedeniyle bir işlem gerçekleştirilemediğinde atılan InvalidOperationException örneğidir.

Sizin durumunuzda, Oturum Açma (kullanıcı adı, şifre) gibi bir yöntem çağrılırsa, kullanıcı adı geçerli değilse, gerçekten bir UserNameNotValidException veya şifre yanlışsa PasswordNotCorrectException özelliğinin kullanılması doğrudur. Kullanıcı, sağlanan parametreleri kullanarak oturum açamaz (yani, kimlik doğrulamasını ihlal edeceği için imkansızdır), bu nedenle bir İstisna atın. Her ne kadar iki istisna ArgumentException devralmak olabilir.

Bir oturum açma hatası çok yaygın olabileceğinden bir İstisna atmak istemiyorsanız, bir strateji bunun yerine farklı hataları temsil eden türleri döndüren bir yöntem oluşturmaktır. İşte bir örnek:

{ // class
    ...

    public LoginResult Login(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            return new UserInvalidLoginResult(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            return new PasswordInvalidLoginResult(user, password);
        }
        else
        {
            return new SuccessfulLoginResult();
        }
    }

    ...
}

public abstract class LoginResult
{
    public readonly string Message;

    protected LoginResult(string message)
    {
        this.Message = message;
    }
}

public class SuccessfulLoginResult : LoginResult
{
    public SucccessfulLogin(string user)
        : base(string.Format("Login for user '{0}' was successful.", user))
    { }
}

public class UserInvalidLoginResult : LoginResult
{
    public UserInvalidLoginResult(string user)
        : base(string.Format("The username '{0}' is invalid.", user))
    { }
}

public class PasswordInvalidLoginResult : LoginResult
{
    public PasswordInvalidLoginResult(string password, string user)
        : base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
    { }
}

Çoğu geliştiriciye, onları fırlatmanın neden olduğu ek yük nedeniyle İstisnalardan kaçınmaları öğretilir. Kaynağa duyarlı olmak harikadır, ancak genellikle uygulama tasarımınızın pahasına değildir. Muhtemelen iki İstisnalarınızı atmamanızın size söylenmesinin nedeni budur. İstisnaların kullanılıp kullanılmayacağı genellikle Kural Dışı Durumun ne sıklıkta gerçekleşeceğine bağlıdır. Oldukça yaygın veya oldukça beklenen bir sonuç ise, çoğu geliştiricinin İstisnalardan kaçınacağı ve bunun yerine kaynakların sözde tüketimi nedeniyle başarısızlığı göstermek için başka bir yöntem oluşturacağı zamandır.

Try () desenini kullanarak, az önce anlatıldığı gibi bir senaryoda Özel Durumlar kullanmaktan kaçınmanın bir örneği:

public class ValidatedLogin
{
    public readonly string User;
    public readonly string Password;

    public ValidatedLogin(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            throw new UserInvalidException(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            throw new PasswordInvalidException(password);
        }

        this.User = user;
        this.Password = password;
    }

    public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
    {
        if (IsInvalidUser(user) || 
            IsInvalidPassword(user, password))
        {
            return false;
        }

        validatedLogin = new ValidatedLogin(user, password);

        return true;
    }
}

1

Bana göre temel soru, bir koşul oluştuğunda arayanın normal program akışına devam etmek isteyip istemeyeceği olmalıdır. Bilmiyorsanız, ya ayrı bir doSomething ve trySomething yöntemlerine sahip olun, burada eski bir hata döndürür ve ikincisi vermez ya da başarısız olursa bir istisnanın atılıp atılmayacağını belirtmek için bir parametreyi kabul eden bir rutine sahip olur). Uzak bir sisteme komut göndermek ve yanıtları bildirmek için bir sınıf düşünün. Belirli komutlar (örn. Yeniden başlatma) uzak sistemin yanıt göndermesine neden olur, ancak belirli bir süre boyunca yanıt vermemeye başlar. Bu nedenle, bir "ping" komutu gönderebilmek ve uzak sistemin bir istisna atmak zorunda kalmadan makul bir süre içinde yanıt verip vermediğini bulmak faydalıdır. t (arayan muhtemelen ilk birkaç "ping" girişiminin başarısız olmasını beklerdi, ancak sonunda sonuçta işe yarayacaktır). Öte yandan, bir komut dizisi varsa:

  exchange_command ("açık geçici dosya");
  exchange_command ("geçici dosya verilerini yaz {whatever}");
  exchange_command ("geçici dosya verilerini yaz {whatever}");
  exchange_command ("geçici dosya verilerini yaz {whatever}");
  exchange_command ("geçici dosya verilerini yaz {whatever}");
  exchange_command ("yakın geçici dosya");
  exchange_command ("geçici dosyayı dosya dosyasına kopyala");

herhangi bir işlemin tüm diziyi iptal edememesi istenir. Her işlem başarılı olduğundan emin olmak için kontrol edilebilir, ancak bir komut başarısız olursa exchange_command () yordamının bir istisna atması daha yararlı olur.

Aslında, yukarıdaki senaryoda, bir dizi hata işleme modunu seçmek için bir parametreye sahip olmak yararlı olabilir: asla istisnalar atmayın, yalnızca iletişim hataları için istisnalar atmayın veya bir komutun " "gösterge.


1

"PasswordNotCorrectException" özel durumlar için iyi bir örnek değildir. Parolalarını yanlış anlayan kullanıcılar beklenmelidir, bu nedenle IMHO için pek de istisna değildir. Muhtemelen ondan kurtuldunuz, güzel bir hata mesajı gösterdiniz, bu yüzden sadece bir geçerlilik kontrolü.

İşlenmeyen istisnalar yürütmeyi sonunda durduracaktır - ki bu iyidir. Yanlış, null veya hata kodları döndürüyorsanız, programın durumuyla tek başınıza ilgilenmeniz gerekir. Bir yerdeki koşulları kontrol etmeyi unutursanız, programınız yanlış verilerle çalışmaya devam edebilir ve ne olduğunu ve nerede olduğunu bulmakta zorlanabilirsiniz .

Tabii ki, aynı yakalama ifadeleriyle aynı soruna neden olabilirsiniz, ancak en azından bunları tespit etmek daha kolaydır ve mantığı anlamanızı gerektirmez.

Temel bir kural olarak:

Onları istemediğiniz veya bir hatadan kurtulamadığınız her yerde kullanın.


0

Bu koşullar için biraz genel istisnalar kullanabilirsiniz. Örneğin ArgumentException, bir yöntemin parametreleriyle (ArgumentNullException hariç) bir şey ters gittiğinde kullanılmalıdır. Genellikle LessThanZeroException, NotPrimeNumberException vb gibi istisnalara ihtiyacınız olmaz. Yönteminizin kullanıcısını düşünün. Özellikle ele almak isteyeceği koşulların sayısı, yönteminizin atması gereken istisna türlerinin sayısına eşittir. Bu şekilde, ne kadar ayrıntılı istisnalarınız olacağını belirleyebilirsiniz.

Bu arada, her zaman kütüphanelerinizin kullanıcılarına istisnaları önlemek için bazı yollar sağlamaya çalışın. TryParse iyi bir örnektir, int.Parse kullanmanız ve bir istisna yakalamanız gerekmez. Sizin durumunuzda, kullanıcı adının geçerli olup olmadığını veya parolanın doğru olup olmadığını kontrol etmek için bazı yöntemler sağlamak isteyebilirsiniz, böylece kullanıcılarınız (veya siz) çok fazla istisna işleme gerekmeyecektir. Bu, umarım daha fazla okunabilir kod ve daha iyi performans sağlar.


0

Nihayetinde karar, istisna yönetimi kullanarak veya durum kodları döndürmek gibi kendi evinizde kullandığınız mekanizma yoluyla bunun gibi uygulama düzeyindeki hatalarla başa çıkmanın daha yararlı olup olmadığına karar verir. Hangisinin daha iyi olduğuna dair sert ve hızlı bir kural olduğunu düşünmüyorum, ancak şunu düşünürdüm:

  • Kodunuzu kim arıyor? Bu bir tür herkese açık bir API mı yoksa dahili bir kütüphane mi?
  • Hangi dili kullanıyorsun Örneğin, Java ise, (işaretli) bir istisna atmak, yoksayılabilecek bir dönüş durumunun aksine, bu hata koşulunu bir şekilde ele almak için arayana açık bir yük getirir. Bu iyi ya da kötü olabilir.
  • Aynı uygulamadaki diğer hata durumları nasıl ele alınır? Arayanlar, sistemdeki hiçbir şeye benzemeyen hataları kendine özgü bir şekilde işleyen bir modülle uğraşmak istemeyecektir.
  • Söz konusu rutinde kaç şey yanlış gidebilir ve bunlar nasıl farklı şekilde ele alınır? Farklı hataları işleyen bir dizi catch bloğu ile hata kodundaki bir anahtar arasındaki farkı düşünün.
  • Geri göndermeniz gereken hata hakkında yapılandırılmış bilgileriniz var mı? Bir istisna atmak, bu bilgileri bir durum döndürmekten daha iyi bir yer sağlar.

0

İki ana istisna sınıfı vardır:

1) Sistem istisnası (örn. Veritabanı bağlantısı kesildi) veya 2) Kullanıcı istisnası. (örn. Kullanıcı girişi doğrulaması, 'şifre yanlış')

Kendi Kullanıcı İstisna Sınıfımı oluşturmayı yararlı buldum ve bir kullanıcı hatası atmak istediğimde farklı bir şekilde ele alınmasını istiyorum (yani kullanıcıya gösterilen hata hata) sonra ana hata işleyicimde tek yapmam gereken nesne türünü kontrol etmektir :

            If TypeName(ex) = "UserException" Then
               Display(ex.message)
            Else
               DisplayError("An unexpected error has occured, contact your help  desk")                   
               LogError(ex)
            End If

0

Bir istisnanın uygun olup olmadığına karar verirken düşünülmesi gereken bazı yararlı şeyler:

  1. istisna adayı gerçekleştikten sonra hangi düzeyde kod çalıştırmak istediğinizi, yani çağrı yığınının kaç katmanının gevşemesi gerektiğini unutmayın. Genellikle bir istisnayı, gerçekleştiği yere olabildiğince yakın işlemek istersiniz. Kullanıcı adı / şifre doğrulaması için, normalde bir istisna balonuna izin vermek yerine aynı kod bloğundaki hataları işlersiniz. Yani bir istisna muhtemelen uygun değildir. (OTOH, başarısız üç giriş denemesinden sonra, kontrol akışı başka bir yere kayabilir ve burada bir istisna uygun olabilir.)

  2. Bu olay bir hata günlüğünde görmek istediğiniz bir şey mi? Her istisna bir hata günlüğüne yazılmaz, ancak bir hata günlüğündeki bu girişin yararlı olup olmadığını sormak yararlı olur - yani, bu konuda bir şeyler yapmaya çalışacaksınız ya da yok saydığınız çöp olabilirsiniz.

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.