Java'da işaretli veya denetlenmeyen istisnaları anlama


703

Joshua Bloch " Etkili Java " dedi

Kurtarılabilir durumlar için işaretli istisnalar ve programlama hataları için çalışma zamanı istisnaları kullanın (2. sürümde Madde 58)

Bakalım bunu doğru anladım.

İşte kontrol edilmiş bir istisna hakkındaki anlayışım:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. Yukarıdakiler kontrol edilmiş bir istisna olarak değerlendirildi mi?

2. RuntimeException denetlenmeyen bir istisna mı?

İşte denetlenmeyen bir istisna konusundaki anlayışım:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. Şimdi, yukarıdaki kod da kontrol edilen bir istisna olamaz mı? Böyle bir durumu düzeltmeye çalışabilir miyim? Yapabilirmiyim? (Not: 3. sorum catchyukarıdakilerin içinde )

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. İnsanlar bunu neden yapıyor?

public void someMethod throws Exception{

}

Neden istisnanın patlamasına izin veriyorlar? Hatayı daha erken ele almıyor mu? Neden kabarcıklı?

6. İstisnayı tam olarak patlatmalı mıyım veya İstisna kullanarak maskelemeli miyim?

Aşağıda okumalarım

Java'da ne zaman işaretli bir istisna oluşturmalıyım ve ne zaman bir çalışma zamanı istisnası olmalı?

İşaretli ve işaretsiz istisnalar ne zaman seçilir?


6
Denetlenmeyen bir istisna için harika bir örneğim var. Her DataSerieszaman zamana bağlı sırada kalması gereken verileri tutan bir sınıfım var. A'nın DataPointsonuna yeni eklemek için bir yöntem vardır DataSeries. Kodumun tamamı proje boyunca doğru çalışıyorsa DataPoint, sonuna zaten bitiş tarihi olan bir tarihe asla sonuna eklenmemelidir. Tüm projedeki her modül bu gerçekçilik ile inşa edilmiştir. Ancak, bu koşulu kontrol ediyorum ve eğer olursa kontrolsüz bir istisna atarım. Neden? Eğer olursa, bunu kimin yaptığını bilmek ve düzeltmek istiyorum.
Erick Robertson

3
Daha fazla karışıklık eklemek için. Birçok kişi ~ 10 yıl önce kontrol edilen istisnaları savunuyorlardı, ama bugünkü manzara gittikçe daha fazla "kontrol edilen istisnalar kötü" yönünde ilerliyor. (Ancak ben buna katılmıyorum)
Kaj

10
Bir istisnayı yalnızca onunla yararlı bir şeyiniz olduğunda işlemek için yararlıdır, aksi takdirde arayanın bunu yapmasına izin vermelisiniz. Oturum açmak ve gerçekleşmemiş gibi davranmak genellikle yararlı değildir. Sadece atmak anlamsız. Bir RuntimeException içinde kaydırma, bazılarının düşündüğü kadar yararlı değildir, derleyicinin size yardımcı olmasını durdurur. (IMHO)
Peter Lawrey

40
İşaretli / işaretsiz istisnaların kapsamlı yanıltıcı koşullarını kullanmayı bırakmalıyız . Onlar çağrılmalıdır check-görevlendirilmiş vs check-olmayan-zorunlu istisnalar.
Blessed Geek

3
Ben de abt ur 5 nokta genel void method_name atar istisna {} neden bazı insanlar bunu yapmak düşündüm?
Maveň ツ

Yanıtlar:


475

Birçok kişi, kontrol edilen istisnaların (yani açıkça yakalamanız veya tekrar aramanız gereken durumlar) hiç kullanılmaması gerektiğini söylüyor. Örneğin C # 'da elendi ve çoğu dilde yok. Böylece her zaman için bir alt sınıf RuntimeExceptionatayabilirsiniz (işaretlenmeyen istisna)

Bununla birlikte, kontrol edilen istisnaların yararlı olduğunu düşünüyorum - API'nizin kullanıcısını istisnai durumun nasıl ele alınacağını düşünmek istediğinizde kullanılırlar (kurtarılabilir ise). Sadece Java platformunda kontrol edilen istisnaların aşırı kullanılması, bu da insanların onlardan nefret etmesini sağlıyor.

İşte konuyla ilgili genişletilmiş görüşüm .

Belirli sorulara gelince:

  1. Is NumberFormatExceptionbir kontrol istisna düşünün?
    No. NumberFormatExceptionişaretlenmez (= öğesinin alt sınıfıdır RuntimeException). Neden? Bilmiyorum. (ancak bir yöntem olmalı isValidInteger(..))

  2. RuntimeExceptionbir kontrolsüz istisna mı?
    Evet kesinlikle.

  3. Burada ne yapmalıyım?
    Bu kodun nerede olduğuna ve ne olmak istediğinize bağlıdır. UI katmanındaysa - yakalayın ve bir uyarı gösterin; eğer servis katmanındaysa - hiç yakalamayın - kabarmasına izin verin. Sadece istisnayı yutmayın. Çoğu durumda bir istisna oluşursa, bunlardan birini seçmelisiniz:

    • giriş yap ve geri dön
    • yeniden düşün (yöntemle atıldığını beyan et)
    • mevcut olanı yapıcıda geçirerek yeni bir istisna oluşturun
  4. Şimdi, yukarıdaki kod da kontrol edilen bir istisna olamaz mı? Böyle bir durumu düzeltmeye çalışabilir miyim? Yapabilirmiyim?
    Öyle olabilirdi. Ama hiçbir şey kontrolsüz istisnayı yakalamanızı engellemez

  5. İnsanlar neden Exceptionatış cümleciklerine ders ekliyor ?
    Çoğu zaman insanlar neyi yakalayacaklarını ve neyi yeniden ele alacaklarını düşünmek için tembel oldukları için. Fırlatma Exceptionkötü bir uygulamadır ve bundan kaçınılmalıdır.

Ne yazık ki, ne zaman yakalayacağınızı, ne zaman tekrar dinleyeceğinizi, ne zaman kontrol edildiğini ve ne zaman kontrol edilmeyen istisnaları kullanacağınızı belirlemenize izin veren tek bir kural yoktur. Bunun çok karışıklığa ve kötü kodlara neden olduğuna katılıyorum. Genel prensip Bloch tarafından belirtilir (bir kısmını alıntılamışsınızdır). Ve genel prensip, onu kaldırabileceğiniz katman için bir istisna yeniden oluşturmaktır.


36
İstisna atma ile ilgili olarak, her zaman insanlar tembel olduğu için değil, aynı zamanda çerçeveleri uyguladığınızda, çerçeve kullanıcılarının herhangi bir istisna atmasına izin vermeniz yaygındır. Sen JSE içinde çağrılabilir arayüzünün imzasını kontrol örneğin edebilirsiniz
Kaj

10
@Kaj - evet, Callable, interceptors ve benzerleri gibi genel şeyler özel durumlardır. Ancak çoğu durumda insanlar tembel oldukları için :)
Bozho

7
re: 3.1 "giriş ve geri dön" Bunu akıllıca yapın. Bu yeme veya saklanma ve istisnalara çok yakındır. Bunu bir problemi göstermeyen, gerçekten olağanüstü olmayan bir şey için yapardım. Günlükler çok kolay sular altında ve göz ardı ediliyor.
Chris

4
"API'nizin kullanıcısını istisnai durumla nasıl başa çıkmaya zorlamak istediğinizde" - istemezlerse kimseyi düşünmeye zorlayamazsınız. Düşünmek istemezlerse, hiçbir şey yapmayan ya da daha kötüsü kritik hata bilgilerini silen ya da bunlara müdahale eden zayıf bir istisna bloğu yazarlar. Bu nedenle, kontrol edilen istisnalar bir başarısızlıktır.
adrianos

3
@adrianos "... istemiyorlarsa kimseyi düşünmeye zorlayamazsın ...." Bu düşünce çizgisiyle derleme hatalarını da kaldırabiliriz .... Seni gerçekten hedeflemiyorum, bunu duydum argüman tekrar tekrar ve yine de Kontrol Edilmiş İstisnalar bir başarısızlık olarak etiketlemek için mümkün olan en kötü açıklama olarak bulmak. Bir yan not olarak, derleme (ve aslında çalışma zamanı hatalarının) tasarımla etkili bir şekilde imkansız hale getirildiği böyle bir dilden önce gördüm. Bu yol çok karanlık yerlere götürdü.
Newtopian

233

Bir şeyin "işaretli bir istisna" olup olmadığı, onu yakalamanız veya yakalama bloğunda ne yaptığınızla ilgili değildir. İstisna sınıflarının bir özelliği. Bir alt sınıfı olan şey Exception hariç için RuntimeExceptionve alt sınıfları bir kontrol istisnadır.

Java derleyicisi sizi denetlenen özel durumları yakalamaya veya yöntem imzasında bildirmeye zorlar. Program güvenliğini arttırması gerekiyordu, ancak çoğunluk düşüncesi, yarattığı tasarım sorunlarına değmeyeceği gibi görünüyor.

Neden istisnanın patlamasına izin veriyorlar? Hata ne kadar erken olursa o kadar iyi değil mi? Neden kabarcıklı?

O bütün Çünkü noktası istisnalar. Bu olasılık olmadan, istisnalara ihtiyacınız olmaz. Hataları, başlangıçta gerçekleştikleri düşük düzeyli yöntemlerle uğraşmaya zorlamak yerine, seçtiğiniz bir düzeyde ele almanızı sağlar.


3
Teşekkür ederim! Zaman zaman krepleme prensibindeki saçmalık yüzünden yöntemlerimden istisnalar atıyorum. Ekibimdeki geliştiricilerden biri, istisna ile başa çıkmak için geçersiz bir xpath ifadesi girmek istiyor. Olası bir olayda bir istisna yakalarlar ve kod incelemesinde bu konuda duyacakları hiçbir şey yapmazlar.
jeremyjjbrown

12
"RuntimeException ve alt sınıfları dışında Throwable'ın bir alt sınıfı olan herhangi bir şey işaretli bir istisnadır." - İfadeniz yanlış. Hata ayrıca Throwable'ı devralır ve işaretlenmez.
Bartzilla

8
@JonasEicher: temel olarak, istisnaların temel bir avantajı, katmanları tamamen hata işleme artefaktlarından arınmış halde tutarken, genellikle oldukça yüksek olan çağrı yığınında hataları işlemek istediğinizi seçmenize izin vermesidir. Kontrol edilen istisnalar tam olarak bu avantajı yok eder. Başka bir problem, kontrol edilen / kontrol edilmeyen ayrımın, istisnaların kavramsal bir kategorizasyonunu da temsil eden istisna sınıfına bağlanmasıdır - zorunlu olarak birbiriyle ilişkili olmayan iki yönü karıştırmak.
Michael Borgwardt

2
"ancak çoğunluk düşüncesi yarattığı tasarım sorunlarına değmeyecek gibi görünüyor." - Atıf lütfen?
kervin

3
@Bartzilla Evet. Bütünlüğü sağlamak için, için javadoc olarak Throwableşunları söylüyor: "Throwable ve kontrol istisna olarak kabul edilmektedir da ya RuntimeException veya Hata alt sınıfı değildir Throwable herhangi bir alt sınıfı"
Bart van Heukelom

74
  1. Yukarıdakiler kontrol edilmiş bir istisna olarak kabul edilir mi? Hayır Bir istisna kullanımı vardır aslında bu bir yapmaz Checked Exceptiono ise RuntimeException.

  2. RuntimeExceptionbir unchecked exception? Evet

Checked ExceptionsHangi subclassesait java.lang.Exception Unchecked Exceptionsolan subclassesbirjava.lang.RuntimeException

İşaretli istisnaları atan aramaların bir try {} bloğuna eklenmesi veya yöntemin arayanında yukarıdaki bir seviyede ele alınması gerekir. Bu durumda, mevcut yöntem, arayanların istisna ile başa çıkmak için uygun düzenlemeleri yapabilmesi için bahsedilen istisnaları attığını beyan etmelidir.

Bu yardımcı olur umarım.

S: Tam istisnayı patlatmalı mıyım yoksa İstisna kullanarak maskeli mi?

A: Evet bu çok iyi bir soru ve önemli tasarım dikkate. İstisna sınıfı çok genel bir istisna sınıfıdır ve dahili düşük seviyeli istisnaları sarmak için kullanılabilir. Özel bir istisna oluşturup içine sarmanız daha iyi olur. Ama, ve büyük bir - Asla altta yatan orijinal kök neden asla belirsiz. Örneğin, Don't everaşağıdakileri yapın -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Bunun yerine aşağıdakileri yapın:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Özgün kök nedenini ortadan kaldırmak, iyileşmenin ötesindeki asıl sebebi, üretim destek ekipleri için, erişim verilen tüm uygulama günlükleri ve hata mesajları olduğu bir kabus. İkincisi daha iyi bir tasarım olmasına rağmen, birçok kişi bunu sık sık kullanmaz, çünkü geliştiriciler sadece altta yatan mesajı arayan kişiye iletemez. Bu yüzden kesin bir not alın: Always pass on the actual exceptionUygulamaya özgü herhangi bir istisna dışında olsun ya da olmasın.

Denemede RuntimeExceptions

RuntimeExceptionGenel bir kural olarak denememelisiniz. Genellikle bir programlama hatasına işaret ederler ve yalnız bırakılmalıdırlar. Bunun yerine programcı, a ile sonuçlanabilecek bazı kodları çağırmadan önce hata durumunu kontrol etmelidir RuntimeException. Örneğin:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Bu kötü bir programlama uygulamasıdır. Bunun yerine bir null kontrol yapılmalıydı -

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Ancak, sayı biçimlendirme gibi böyle bir hata kontrolünün pahalı olduğu zamanlar vardır, bunu düşünün -

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

Burada, çağırma öncesi hata denetimi çabaya değmez, çünkü esas olarak parseInt () yöntemi içindeki tüm dizeden tamsayı dönüşüm kodunu çoğaltmak anlamına gelir - ve bir geliştirici tarafından uygulanırsa hataya açıktır. Yani try-catch ile ortadan kaldırmak daha iyidir.

Yani NullPointerExceptionve NumberFormatExceptionher ikisi de RuntimeExceptions, hata eğilimli kod olası giriş önlemek NullPointerExceptioniçin NumberFormatExceptionaçıkça yakalamak tavsiye ederken bir zarif yakalamak null-check ile değiştirilmesi gerekir .


Teşekkür ederim. Köpürürken bir soru daha exception, tam istisnayı patlatmalı mıyım veya kullanarak maskeliyim Exception. Bazı eski kodların üstüne kod yazıyorum ve Exceptionher yerde kabarcıklı oluyorum . Acaba bu doğru davranış mı?
Thang Pham

1
Bu çok iyi ve önemli bir soru, cevabımı açıklamayı da içerecek şekilde düzenledi.
d-live

Çok teşekkür ederim. Bana içeriğini göstermen mümkün LoginFailureException(sqle)mü?
Thang Pham

1
Bu şeyler için herhangi bir kod yok, ben sadece isimleri vb pişirilir. Java.lang.Exception görürseniz, ikisi java.lang.Throwable kabul 4 yapıcıları vardır. Yukarıdaki pasajlarda bir yapıcıyı LoginFailureExceptiongenişlettiğimizi Exceptionve ilan ettiğimi varsaydımpublic LoginFailureException(Throwable cause) { super(cause) }
d-live

Konu hakkında en iyi cevap. Bence bu istisnalar iyi programlama eksikliği nedeniyle meydana gelir çünkü çalışma zamanı istisnaları yakalanmamalıdır. "Özgün kök nedenleri gömmek, iyileşmenin ötesinde asıl neden, onlara erişim verilen tüm uygulama günlükleri ve hata mesajları olduğu üretim destek ekipleri için bir kabus" kısmına tamamen katılıyorum.
huseyin

19

1. Bir istisnadan emin değilseniz API'yı kontrol edin:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2. Evet ve onu genişleten her istisna.

3. Aynı istisnayı yakalayıp atmaya gerek yoktur. Bu durumda yeni bir Dosya İletişim Kutusu gösterebilirsiniz.

4. FileNotFoundException olduğunu zaten işaretli istisna.

5. someMethodİstisna yakalamak için çağıran yöntemin beklenmesi durumunda , ikincisi atılabilir. Sadece "topu geçer". Kendi özel yöntemlerinize atmak ve bunun yerine genel yönteminizde istisnayı ele almak istiyorsanız bunun kullanımına bir örnek verilebilir.

İyi bir okuma Oracle belgesinin kendisidir: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Tasarımcılar neden kapsamı içinde atılabilecek tüm yakalanmamış kontrol edilmiş istisnaları belirlemeye yönelik bir yöntemi zorlamaya karar verdiler? Bir yöntemle atılabilecek herhangi bir İstisna, yöntemin genel programlama arabiriminin bir parçasıdır. Bir yöntem çağıranlar, bir yöntemin atabilecekleri istisnalar hakkında bilgi sahibi olmalıdır, böylece onlar hakkında ne yapacaklarına karar verebilirler. Bu istisnalar, bu yöntemin programlama arayüzünün parametreleri ve dönüş değeri kadar bir parçasıdır.

Sonraki soru şu olabilir: "Bir yöntemin API'sini belgelemek o kadar iyi ise, istisnalar da dahil, neden çalışma zamanı istisnalarını da belirtmeyesiniz?" Çalışma zamanı istisnaları, bir programlama sorununun sonucu olan sorunları temsil eder ve bu nedenle, API istemci kodunun onlardan kurtarılması veya bunları herhangi bir şekilde işlemesi beklenemez. Bu tür sorunlar arasında sıfıra bölme gibi aritmetik istisnalar; bir nesneye boş bir başvuru yoluyla erişmeye çalışmak gibi işaretçi istisnalar; ve çok büyük veya çok küçük bir dizin yoluyla bir dizi öğesine erişmeye çalışmak gibi dizin oluşturma istisnaları.

Ayrıca Java Dil Spesifikasyonu'nda önemli bir bilgi var :

Fırlatma cümlesinde adı geçen kontrol edilen istisna sınıfları, uygulayıcı ile yöntem veya kurucunun kullanıcısı arasındaki sözleşmenin bir parçasıdır .

Sonuçta IMHO Bunun ne olabilir herhangi yakalamak RuntimeExceptionolanlar sözleşmenin bir parçası değildir olarak aslında uygulama, atılan aynı olmayan işaretli istisnalar korumak için gerekli değildir, ancak zorunlu değildir ve.


Teşekkür ederim. Köpürürken bir soru daha exception, tam istisnayı patlatmalı mıyım veya kullanarak maskeliyim Exception. Bazı eski kodların üstüne kod yazıyorum ve Exceptionher yerde kabarcıklı oluyorum . Acaba bu doğru davranış mı?
Thang Pham

1
@Harry Benden daha fazla bilgiye sahip insanların buna cevap vermesine izin vereceğim: stackoverflow.com/questions/409563/…
Aleadam

10

1) Hayır, NumberFormatException denetlenmeyen bir Özel Durum'dur. Yakalamış olsanız bile (yapmanız gerekmez) işaretlenmedi. Bunun nedeni, bir alt sınıfı IllegalArgumentExceptionolan bir alt sınıfı olmasıdır RuntimeException.

2) RuntimeException tüm denetlenmeyen İstisnaların köküdür. Her alt sınıfı RuntimeExceptionişaretlenmez. Diğer tüm İstisnalar ve ThrowableHatalar (bunlar altında Throwable) dışında kontrol edilir .

3/4) Kullanıcıyı var olmayan bir dosyayı seçtiği konusunda uyarabilir ve yeni bir dosya isteyebilirsiniz. Veya kullanıcıyı geçersiz bir şey girdikleri konusunda bilgilendirmeyi bırakın.

5) Fırlatma ve yakalama 'Exception'kötü bir uygulamadır. Ancak daha genel olarak, arayanın bununla nasıl başa çıkacağına karar verebilmesi için başka istisnalar atabilirsiniz. Örneğin, bazı dosya girişlerini okumak için bir kitaplık yazdıysanız ve yönteminiz varolmayan bir dosyadan geçtiyse, bunu nasıl işleyeceğiniz hakkında hiçbir fikriniz yok. Arayan tekrar sormak veya çıkmak istiyor mu? Böylece İstisnayı zincirden yukarıya arayan kişiye geri atarsınız.

Çoğu durumda, unchecked Exceptionprogramcı girişleri doğrulamaması nedeniyle oluşur ( NumberFormatExceptionilk sorunuzda). Bu yüzden onları yakalamak isteğe bağlıdır, çünkü bu istisnaları üretmekten kaçınmanın daha zarif yolları vardır.


Teşekkür ederim. Köpürürken bir soru daha exception, tam istisnayı patlatmalı mıyım veya kullanarak maskeliyim Exception. Bazı eski kodların üstüne kod yazıyorum ve Exceptionher yerde kabarcıklı oluyorum . Acaba bu doğru davranış mı?
Thang Pham

Ya sadece yönteminizin İstisna atmasını da sağlayabilirsiniz (ki bu ideal değildir). Veya İstisna'yı yakalayın ve daha iyi bir İstisna atın (IOException veya benzeri bir şey). Tüm İstisnalar yapıcılarında bir istisna olarak bir 'neden' olarak kabul edilebilir, bu yüzden bunu kullanmalısınız.
dontocsata

8

İşaretli - Gerçekleşmeye eğilimli. Derleme zamanında kontrol edildi.

Örn .. FileOperations

İşaretlenmedi - Hatalı veriler nedeniyle. Çalışma zamanında kontrol edildi.

Örneğin..

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Burada istisna kötü verilerden kaynaklanır ve hiçbir şekilde derleme süresi boyunca belirlenemez.


6

Kontrol edilen istisnalar derleme zamanında JVM ve kaynaklarla (dosyalar / db / stream / soket vb.) İlgili olarak kontrol edilir. İşaretli istisna nedeni, derleme zamanında kaynaklar yoksa uygulamanın catch / nihayet bloğunda bunu ele almak için alternatif bir davranış tanımlaması gerektiğidir.

İşaretlenmeyen istisnalar yalnızca programsal hatalar, yanlış hesaplama, boş veriler veya hatta iş mantığındaki hatalar çalışma zamanı istisnalarına yol açabilir. Koddaki denetlenmeyen istisnaları işlemek / yakalamak kesinlikle iyidir.

Http://coder2design.com/java-interview-questions/ adresinden alınan açıklama


5

Benim mutlak favori kontrolsüz ve kontrol istisnalar arasındaki farkın açıklaması Java Eğitimi iz makalesinde, "tarafından sağlanır - Tartışma İşaretli İstisnalar " (bu yazının tüm temel almak için üzgünüz - ama, hey, temelleri bazen en iyisidir):

Alt satırdaki kılavuz şudur: Bir istemcinin bir istisnayı kurtarması beklenebiliyorsa, denetlenen bir istisna yapın. İstemci özel durumdan kurtarmak için hiçbir şey yapamazsa, denetlenmeyen bir özel durum haline getirin

"Ne tür bir istisna atmak" kalbi anlamlıdır (bir dereceye kadar) ve yukarıdaki alıntı ve mükemmel bir kılavuz sağlar (bu nedenle, C # 'nin kontrol edilen istisnalardan kurtulduğu - özellikle Liskov'un iddia ettiği gibi) yararlılıkları).

Geri kalanlar mantıklı hale gelir: derleyici hangi istisnalara açıkça cevap vermemi bekler? İstemcinin iyileşmesini beklediğiniz olanlar.


5

Son soruyu cevaplamak için (diğerleri yukarıda iyice cevaplanmış gibi görünüyor), "Tam istisnayı patlatmalı mıyım veya İstisna kullanarak maskeli mi?"

Böyle bir şey demek istediğinizi varsayıyorum:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

Hayır, her zaman mümkün olan en kesin istisnayı veya bunun bir listesini beyan edin . Metodunuzu fırlatma yeteneğine sahip olarak beyan ettiğiniz istisnalar, metodunuz ile arayan arasındaki sözleşmenin bir parçasıdır. Fırlatma "FileNotFoundException", dosya adının geçerli olmaması ve dosyanın bulunamaması anlamına gelir; arayanın bunu akıllıca ele alması gerekir. Fırlatma Exception, "Hey, lanet olası. Anlaşma." Bu çok fakirAPI .

İlk makaledeki yorumlarda "atar" ifadesinin Exceptiongeçerli ve makul bir beyan olduğu bazı örnekler vardır , ancak normalyazacağınız çoğu " " kodu için durum böyle değildir .


Tam olarak, kontrol istisnası beyanınızı kod belgelerinizin bir parçası haline getirin ve ayrıca yazılımınızı kullanan kişiye yardım edin.
Salvador Valencia

5

Çalışma Zamanı İstisnaları : Çalışma zamanı istisnaları, denetlenmeyen istisnalar olarak adlandırılır. Diğer tüm istisnalar kontrol edilen istisnalardır ve java.lang.RuntimeException öğesinden türetilmemiştir.

Kontrol Edilen İstisnalar : bir istisna kodunuzun herhangi bir yerine takılmalıdır. İşaretli bir kural dışı durum atan bir yöntemi çağırırsanız, ancak işaretli kural dışı durumu bir yerde yakalamazsanız, kodunuz derlenmez. Bu yüzden onlara kontrol edilmiş istisnalar denir: derleyici, ele alındıklarını veya beyan edildiklerini kontrol eder.

Java API'sindeki bir dizi yöntem işaretli istisnalar atar, bu nedenle genellikle yazmadığınız yöntemlerle oluşturulan istisnalarla başa çıkmak için istisna işleyicileri yazarsınız.


3

Neden istisnanın patlamasına izin veriyorlar? Hatayı daha erken ele almıyor mu? Neden kabarcıklı?

Örneğin, bazı istemci-sunucu uygulamanız olduğunu ve istemci, bulunamayan bazı kaynaklar için bir istekte bulunduğunu veya kullanıcı isteğini işlerken bazılarının sunucu tarafında oluşmuş olabileceği başka bir hata için istekte bulunduğunu varsayalım istemciye neden istediği şeyi alamadığını söylemek için sunucuda, bu yüzden sunucu tarafında bunu yutmak veya ele almak yerine throw anahtar sözcüğünü kullanarak istisnayı atmak için kod yazılır. bu durumda, istemciye hangi hatanın meydana geldiğini sindirme şansı olmayacaktır.

Not: Hata türünün ne olduğuna ilişkin net bir açıklama vermek için kendi İstisna nesnesimizi oluşturabilir ve istemciye atabiliriz.


İyi bir nokta. Bunun anlamı, mantık akışını kontrol eden ve uygulama için iş mantığını denetleyen en sorumlu katmana kadar kabarcıklamaktır. Örneğin, veritabanı katmanının istemciye kritik bir şeyin eksik veya yanıt vermediği ile iletişim kurması imkansızdır. En üstteki sunucu katmanına ulaştığında, istemcinin görünümünü kritik bir hata mesajı ile yenilemek kolaydır.
Salvador Valencia


3

Sadece kontrol edilen istisnaları kullanmamanız için bazı nedenler eklemek istiyorum. Bu tam bir cevap değil, ama sorunuzun bir kısmını cevapladığını ve diğer birçok yanıtı tamamladığını hissediyorum.

İşaretli istisnalar söz konusu olduğunda, throws CheckedExceptionyöntem imzasında bir yer vardır ( CheckedExceptionişaretli istisnalar olabilir). İmza bir İstisna VERMEZ, İstisnalar atmak uygulamanın bir yönüdür. Arayüzler, yöntem imzaları, ebeveyn sınıfları, bunların hepsi uygulamalarına bağlı OLMAMALIDIR. Burada kontrol edilen İstisnaların kullanımı (aslında throwsyöntem imzasında beyan etmeniz gerektiği gerçeği ), üst düzey arayüzlerinizi bu arayüzlerin uygulamalarınızla bağlar.

Size bir örnek göstereyim.

Bunun gibi güzel ve temiz bir arayüze sahip olalım

public interface IFoo {
    public void foo();
}

Şimdi yöntemin birçok uygulamaları yazabilir foo()bunlar gibi,

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Sınıf Foo gayet iyi. Şimdi Bar sınıfında ilk denemeyi yapalım

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

Bu sınıf Bar derlenmeyecek. InterruptedException işaretli bir istisna olduğundan, onu yakalamanız (try-catch inside method foo () ile) veya attığınızı ( throws InterruptedExceptionyöntem imzasına ekleyerek) bildirmeniz gerekir . Bu istisnayı burada yakalamak istemediğim için (yukarı doğru yayılmasını istiyorum, böylece başka bir yerde düzgün bir şekilde başa çıkabiliyorum), imzayı değiştirelim.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

Bu sınıf Bar da derlenmeyecek! İmzaları farklı olduğu için Bar'ın foo () yöntemi IFoo'nun yöntem foo () yöntemini geçersiz kılmaz. @Override ek açıklamasını kaldırabilirim, ancak IFoo arayüzü gibi IFoo foo;ve daha sonra hangi uygulamayı kullanmak istediğime karar vermek gibi arayüze karşı programlamak istiyorum foo = new Bar();. Bar'ın yöntem foo () IFoo'nun yöntem foo'yu geçersiz kılmazsa, yaptığımda foo.foo();Bar'ın foo () uygulamasını çağırmaz.

Bar'ın public void foo() throws InterruptedExceptiongeçersiz kılma IFoo'sunu yapmak için IFoo'nun yöntem imzasına eklemem public void foo()GEREKİR throws InterruptedException. Ancak bu, foo () yönteminin imzası IFoo'nun yöntem imzasından farklı olduğu için Foo sınıfımla ilgili sorunlara neden olacaktır. Ayrıca, eğerthrows InterruptedException Foo'nun yöntemi foo () Foo'nun yöntemi foo () bir InterruptedException atıldığını ancak asla bir InterruptedException atıldığını bildiren başka bir hata alırsınız.

Gördüğünüz gibi (bu şeyleri açıklamak için iyi bir iş yapmış olsaydım), InterruptedException gibi kontrol edilmiş bir istisnayı attığım gerçeği beni arayüz IFoo'yu uygulamalarından birine bağlamaya zorluyor, bu da IFoo'nun tahribatına neden oluyor diğer uygulamalar!

Bu, kontrol edilen istisnaların KÖTÜ olmasının önemli bir nedenidir. Kapaklar halinde.

Çözümlerden biri, denetlenen istisnayı yakalamak, denetlenmeyen bir özel duruma sarmak ve denetlenmeyen özel durumu atmaktır.


2
Evet, bu kötü çünkü onu yakalamak istemediğini söyledin. Ancak IFOO'nun imzasını etkilememek için yapmanız gerekecek. Bunu bir istisna yakalamaktan kaçınmak için tüm arayüzlerimin imzalarını yeniden dengelemek yerine bunu yapmayı tercih ederim (sadece istisnalar kötü olduğu için).
Salvador Valencia

Evet katılıyorum. Bir şey hakkında biraz belirsizdim. Yaymak için bir istisna istiyorum, böylece başka bir yerde başa çıkabilirim. Çözümlerden biri InterruptedException özel durumunu yakalamak ve denetlenmeyen bir özel durum oluşturmaktır. yani kontrol edilen istisnalardan kaçınırız ve kontrol edilmeyen istisnaları
geçeriz

"Ancak bu, foo () yönteminin imzası IFoo'nun yöntem imzasından farklı olduğu için Foo sınıfımla ilgili sorunlara neden olacak". Sadece fikrinizi test ettim ve throws InterruptedExceptionIFoo'nun yöntem imzasını herhangi bir uygulamaya atmadan eklememiz bile derlenebilir . Yani gerçekten herhangi bir soruna neden olmaz. Bir arayüzde her yöntemi imza atmak yaparsanız Exception, bir uygulamaya bir istisna atma veya atmama seçeneği verir (herhangi bir istisna, Exceptiontüm istisnaları kapsama olarak ).
Flyout91

Bununla birlikte, kafa karıştırıcı olabileceğini itiraf ediyorum çünkü böyle bir inteface uygulayacak ve "Eklenmemiş yöntemler ekle" gibi bir şeye tıkladığınızda, throw Exceptionuygulamanız hiçbir şey atmayacak veya daha özel bir istisna. Ama yine de, her zaman bir Arayüz yöntemi için İstisna atmanın iyi bir uygulama olduğunu hissediyorum, çünkü yine, kullanıcıya bir şey atma veya atmama seçeneği veriyor.
Flyout91

Bu, tüm noktayı kaçırır. Bir arayüzün amacı, bir müşterinin yerine getirilmesi gereken sözleşmeyi beyan etmektir. Bu, işleyebileceği hata senaryolarını içerebilir. Bir uygulama bir hatayla karşılaştığında, bu hatayı istemci arabirimi tarafından bildirilen uygun soyut başarısızlıkla eşleştirmelidir.
erickson

3
  • Java iki istisna kategorisini birbirinden ayırır (işaretli ve işaretsiz).
  • Java, denetlenen istisnalar için yakalama veya bildirilen bir gereksinimi zorlar.
  • Bir istisnanın türü, bir istisnanın işaretlenip işaretlenmeyeceğini belirler.
  • subclassesSınıfın doğrudan veya dolaylı olduğu tüm özel durum türleri RuntimeException denetlenmeyen özel durumdur.
  • Sınıftan miras alan Exceptionancak sınıfta olmayan tüm sınıflar RuntimeExceptionkabul edilir checked exceptions.
  • Error sınıfından miras alan sınıfların işareti kaldırılır.
  • Derleyici, yöntemin atıp atmadığını belirlemek için her yöntem çağrısını ve yavaşlamasını denetler checked exception.
    • Eğer öyleyse, derleyici istisnanın yakalanmasını veya atar maddesinde beyan edilmesini sağlar.
  • Yakalama veya bildirme gereksiniminin bildirme bölümünü karşılamak için, istisnayı oluşturan yöntemin bir throwscümle içermesi gerekir checked-exception.
  • Exception sınıflar, yakalanacak veya beyan edilecek kadar önemli kabul edildiğinde kontrol edilecek şekilde tanımlanır.

2

İşte karar vermenize yardımcı olabilecek basit bir kural. Java'da arayüzlerin nasıl kullanıldığı ile ilgilidir.

Sınıfınızı alın ve bunun için bir arabirim sınıfın işlevselliğini açıklayacak, ancak temeldeki uygulamalardan hiçbirini tanımlayamayacak şekilde bir arabirim tasarladığınızı hayal edin (bir arabirimin olması gerektiği gibi). Sınıfı başka bir şekilde uygulayabileceğinizi düşünün.

Arayüzün yöntemlerine bakın ve atabilecekleri istisnaları göz önünde bulundurun:

Altta yatan uygulamaya bakılmaksızın (diğer bir deyişle, yalnızca işlevselliği açıklar) bir yöntemle bir istisna atılabilirse, muhtemelen arabirimde denetlenen bir istisna olmalıdır.

Altta yatan uygulama bir istisnadan kaynaklanıyorsa, arayüzde olmamalıdır. Bu nedenle, sınıfınızda denetlenmeyen bir özel durum olmalıdır (arabirim imzasında denetlenmeyen özel durumların görünmesi gerekmediğinden) veya arabirim yönteminin bir parçası olan denetlenen bir özel durum olarak sarmanız ve yeniden denemeniz gerekir.

Sarmanız ve yeniden düşünmeniz gerekip gerekmediğine karar vermek için, bir arabirim kullanıcısının istisna koşulunu hemen ele almasının mantıklı olup olmadığını veya istisna o kadar genel olup olmadığını düşünmelisiniz ve bu konuda yapabileceğiniz hiçbir şey yoktur ve yığını yay. Sarılmış istisna, tanımladığınız yeni arayüzün işlevselliği olarak ifade edildiğinde mantıklı mı yoksa sadece diğer yöntemlerde de olabilecek olası hata durumları için bir taşıyıcı mı? Birincisi, yine de kontrol edilmiş bir istisna olabilir, aksi takdirde işaretlenmemelidir.

Genellikle istisnaları "yakala" (planla ve geri al) planlamamalısınız. Ya bir istisna arayan tarafından ele alınmalıdır (bu durumda kontrol edilir) ya da üst düzey bir işleyiciye kadar devam etmelidir (bu durumda işaretlenmemişse en kolayıdır).


2

Sadece bir koda işaretli bir istisna atarsanız ve yakalama yukarıdaki birkaç düzeyse, siz ve yakalama arasındaki her yöntemin imzasındaki istisnayı bildirmeniz gerektiğini belirtmek için. Dolayısıyla, kapsülleme bozuktur çünkü fırlatma yolundaki tüm fonksiyonlar bu istisnanın ayrıntıları hakkında bilgi sahibi olmalıdır.


2

Kısacası, modülünüzün veya yukarıdaki modüllerin çalışma zamanı sırasında işlemesi gereken istisnalara denetlenmiş istisnalar denir; diğerleri kontrol edilmeyen istisnalardır ya RuntimeExceptionda Error.

Bu videoda, Java'daki işaretli ve işaretsiz istisnaları açıklar:
https://www.youtube.com/watch?v=ue2pOqLaArw


1

Bunların hepsi kontrol edilmiş istisnalardır. İşaretlenmeyen özel durumlar RuntimeException öğesinin alt sınıflarıdır. Karar, onları nasıl ele alacağınız değil, kodunuz onları atmalıdır. Derleyicinin size bir özel durum işlemediğinizi söylemesini istemiyorsanız, denetlenmeyen (RuntimeException alt sınıfı) özel durumu kullanırsınız. Bunlar, yetersiz bellek hataları ve benzerleri gibi kurtarılamadığınız durumlar için kaydedilmelidir.


um. NumberFormatException kontrol edilen bir istisna ise, dediğiniz gibi , RuntimeException kaynağından devralındığı gerçeğiyle çelişmiyor mu?
eis

Üzgünüm, çok net değildim. Ben NumberFormatException değil FileNotFoundException atıfta. Onun # 2 & # 4 dayanarak, Checked vs Unchecked, onu yakaladıktan sonra istisnayı nasıl ele aldığınıza dayandığını düşünüyordu. Nasıl tanımlandığı değil.
23'te mamboking

-1

Herhangi biri, kontrol edilen istisnaları beğenmemek için başka bir kanıt istiyorsa, popüler JSON kütüphanesinin ilk birkaç paragrafına bakın:

"Bu, işaretli bir istisna olmasına rağmen, nadiren kurtarılabilir. Çoğu arayan, bu istisnayı kontrol edilmeyen bir istisnaya sarmalı ve yeniden yanıtlamalıdır:"

Öyleyse neden dünyada "basitçe sarmalıysak", neden geliştiriciler istisnayı kontrol etmeye devam etsin ki? lol

http://developer.android.com/reference/org/json/JSONException.html


4
Çünkü sadece arayanların çoğu değil, tüm arayanlar değil. İstisnanın işaretlenmiş olması, arayanın "en" arayanlardan biri mi, yoksa istisnayı ele alabilecek ve alması gereken azınlıklardan biri olup olmadığını düşünmesi gerektiği anlamına gelir.
Warren Dew

1
Yaptığınız her çağrı için hataları kontrol etmek isterseniz, C'ye "geri dönün" İstisnalar, kodunuzu kirletmeden normal program yürütmesini anormalden ayırmanın bir yoludur. İstisnalar, bir hatayı bir düzeyde sessizce göz ardı edemezsiniz .
Slawomir

-1

Kontrol Edilen İstisnalar :

  • Programın çalışma zamanında düzgün bir şekilde yürütülmesi için derleyici tarafından kontrol edilen istisnalara Checked Exception denir.

  • Bunlar derleme zamanında gerçekleşir.

  • Bunlar doğru şekilde ele alınmazsa, derleme zamanı hatası verir (İstisna Değil).
  • İstisna sınıfının RuntimeException dışındaki tüm alt sınıfları Checked Exception'dır.

    Varsayımsal Örnek - Diyelim ki sınav için evden ayrılıyorsunuz, ancak Hall Biletinizi evde alıp almadığınızı (derleme zamanı) kontrol ederseniz, Sınav Salonu'nda (çalışma zamanı) herhangi bir sorun olmayacaktır.

İşaretlenmeyen İstisna :

  • Derleyici tarafından denetlenmeyen özel durumlara Denetlenmeyen Özel Durumlar denir.

  • Bunlar çalışma zamanında meydana gelir.

  • Bu özel durumlar doğru şekilde ele alınmazsa, derleme zamanı hatası vermezler. Ancak program çalışma zamanında erken sonlandırılacaktır.

  • RunTimeException ve Error öğelerinin tüm alt sınıfları denetlenmeyen istisnalardır.

    Varsayımsal Örnek - Diyelim ki sınav salonunuzdasınız ama okulunuz bir şekilde o anda hiçbir şey yapamayacağınız bir yangın kazası geçirdi (çalışma zamanında anlamına gelir), ancak daha önce önlemler alınabilir (derleme zamanı).


-2

Tüm istisnalar istisnalar kontrol edilmelidir.

  1. İşaretlenmeyen istisnalar sınırsız gotoslardır. Ve sınırsız gotolar kötü bir şey olarak kabul edilir.

  2. İşaretlenmeyen özel durumlar kapsüllemeyi keser. Bunları doğru bir şekilde işlemek için, çağrı ağacında atıcı ve yakalayıcı arasındaki tüm işlevlerin, hataları önlemek için bilinmesi gerekir.

  3. İstisnalar, onları atan işlevdeki hatalardır, ancak bunları işleyen işlevdeki hatalar değildir. İstisnaların amacı, bunun başka bir bağlamda hata olup olmadığına karar vermesini erteleyerek programa ikinci bir şans vermektir. Doğru karar ancak diğer bağlamda verilebilir.

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.