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


213

Java'da (veya işaretli istisnaları olan başka bir dilde), kendi istisna sınıfınızı oluştururken, işaretlenip işaretlenmeyeceğine nasıl karar verirsiniz?

İçgüdüm, arayan kişinin üretken bir şekilde iyileşebileceği durumlarda, kontrol edilmeyen bir istisna olarak kurtarılamayan durumlar için daha fazla olacağı durumlarda, kontrol edilen bir istisnanın çağrılacağını söylemek, ancak başkalarının düşüncelerine ilgi duyuyorum.


11
Barry Ruzek, kontrol edilen veya kontrol edilmeyen istisnaları seçme konusunda mükemmel bir rehber yazmıştır .
sigget

Yanıtlar:


241

İşaretli İstisnalar, ne zaman kullanılması gerektiğini anladığınız sürece mükemmeldir. Java çekirdeği API'si, SQLException (ve bazen IOException için) için bu kurallara uymuyor, bu yüzden çok korkunçlar.

İşaretli İstisnalar , öngörülebilir , ancak kurtarılması makul olan önlenemeyen hatalar için kullanılmalıdır .

İşaretlenmeyen İstisnalar diğer her şey için kullanılmalıdır.

Bunu sizin için yıkacağım, çünkü çoğu insan bunun ne anlama geldiğini yanlış anlıyor.

  1. Öngörülebilir ancak önlenemez : Arayan, giriş parametrelerini doğrulamak için gücü dahilinde her şeyi yaptı, ancak kontrolleri dışındaki bazı durumlar işlemin başarısız olmasına neden oldu. Örneğin, bir dosyayı okumayı denersiniz, ancak biri dosyayı kontrol edip etmediğini ve okuma işleminin başladığı zaman arasında siler. İşaretli bir istisna bildirerek, arayan kişiye bu hatayı önceden tahmin etmesini söylersiniz.
  2. Kurtarmak için makul : Arayanlara iyileşemeyecekleri istisnaları öngörmelerini söylemeye gerek yok. Bir kullanıcı var olmayan bir dosyadan okumaya çalışırsa, arayan yeni bir dosya adı isteyebilir. Öte yandan, yöntem bir programlama hatası (geçersiz yöntem bağımsız değişkenleri veya buggy yöntem uygulaması) nedeniyle başarısız olursa, uygulamanın ortasında yürütme sorununu gidermek için yapabileceği hiçbir şey yoktur. Yapabileceği en iyi şey sorunu günlüğe kaydetmek ve geliştiricinin daha sonra düzeltmesini beklemektir.

Attığınız istisna yukarıdaki koşulların tümünü karşılamadığı sürece Kontrol Edilmemiş İstisna kullanmalıdır.

Her seviyede yeniden değerlendirme : Bazen işaretli istisnayı yakalayan yöntem, hatayı işlemek için doğru yer olmayabilir. Bu durumda, kendi arayanlarınız için neyin makul olduğunu düşünün. İstisna tahmin edilebilir, önlenemez ve onlardan kurtulmaları için makul ise, kendiniz kontrol edilmiş bir istisna atmalısınız. Değilse, istisnayı denetlenmeyen bir istisnaya sarmalısınız. Bu kuralı izlerseniz, kontrol ettiğiniz istisnaları kontrol edilmemiş istisnalara dönüştürür ve içinde bulunduğunuz katmana bağlı olarak tersini görürsünüz.

Hem kontrol edilen hem de kontrol edilmeyen istisnalar için doğru soyutlama seviyesini kullanın . Örneğin, iki farklı uygulamaya (veritabanı ve dosya sistemi) sahip bir kod deposu, SQLExceptionveya işlevini uygulayarak uygulamaya özgü ayrıntıları göstermekten kaçınmalıdır IOException. Bunun yerine, istisnayı tüm uygulamaları kapsayan bir soyutlama içine almalıdır (örn. RepositoryException).


2
"bir dosyayı okumaya çalışıyorsunuz ancak birisi dosyanın var olup olmadığını kontrol ettiğiniz zaman ile okuma işleminin başladığı zaman arasında siler." => Bu nasıl 'beklenen'? Bana öyle geliyor ki: Beklenmedik ve önlenebilir .. Kim bir dosyanın sadece 2 ifade arasında silinmesini bekleyebilir?
Koray Tugay

9
@KorayTugay Beklenen , senaryonun tipik olduğu anlamına gelmez. Sadece bu hatayı vaktinden önce öngörebileceğimiz anlamına gelir (önceden tahmin edilemeyen programlama hataları ile karşılaştırıldığında). Önlenemez , programcının kullanıcı veya diğer uygulamaların var olup olmadığını kontrol ettiğimiz zaman ile okuma işleminin başladığı zaman arasında bir dosyayı silmesini önlemek için yapabileceği hiçbir şey olmadığı anlamına gelir.
Gili

Yani yöntem içinde veritabanı ile ilgili herhangi bir sorun kontrol edilen istisna atmak gerekir?
ivanjermakov

59

Gönderen Bir Java Learner :

Bir kural dışı durum oluştuğunda, kural dışı durumu yakalamanız ve işlemeniz gerekir ya da derleyiciye yönteminizin bu kural dışı durumu verdiğini bildirerek işleyemeyeceğinizi bildirmeniz gerekir, o zaman yönteminizi kullanan kodun bu kural dışı durumu ( ayrıca işleyemezse istisnayı attığını bildirmeyi de seçebilir).

Derleyici iki şeyden birini (yakala veya bildir) yaptığımızı kontrol edecektir. Buna bunlara Checked istisnaları denir. Ancak Hatalar ve Çalışma Zamanı İstisnaları derleyici tarafından denetlenmez (yakalamayı veya bildirmeyi seçebilmenize rağmen, gerekli değildir). Yani, bu ikisine Denetlenmeyen istisnalar denir.

Hatalar, sistemin çökmesi gibi uygulama dışında meydana gelen durumları temsil etmek için kullanılır. Çalışma zamanı istisnaları genellikle uygulama mantığındaki hata nedeniyle oluşur. Bu durumlarda hiçbir şey yapamazsınız. Çalışma zamanı istisnası oluştuğunda, program kodunuzu yeniden yazmanız gerekir. Yani, bunlar derleyici tarafından kontrol edilmez. Bu çalışma zamanı istisnaları geliştirme ve test döneminde ortaya çıkacaktır. Sonra bu hataları gidermek için kodumuzu yeniden düzenlememiz gerekir.


13
Ortodoks görüş bu. Ancak bu konuda çok fazla tartışma var.
artbristol

49

Kullandığım kural: asla denetlenmeyen istisnalar kullanmayın! (veya etrafında bir yol göremediğinizde)

Bunun tersi için çok güçlü bir durum var: Asla işaretli istisnaları kullanmayın. Tartışmada taraf tutma konusunda isteksizim, ancak kontrol edilen istisnaların getirilmesinin, görüş alanında yanlış bir karar olduğu konusunda geniş bir fikir birliği var gibi görünüyor. Lütfen elçiyi vurmayın ve bu argümanlara bakın .


3
IMHO, bir yöntemin belirli bir kod bloğunda çağrılan yöntemlerin belirli istisnaları (veya herhangi birini) atmasını beklemediğini ve herhangi bir işaretli olduğunu bildirmenin kolay bir yolu olsaydı, kontrol edilen istisnalar önemli bir varlık olabilirdi bu beklentiye aykırı olan istisnalar, başka bir istisna türüne sarılmalı ve yeniden oluşturulmalıdır. Kodun kontrol edilen bir istisna ile başa çıkmaya hazır olmadığı zamanın% 90'ının, böyle bir sarma ve tekrarlamanın bununla başa çıkmanın en iyi yolu olacağını, ancak nadiren yapılan bir dil desteği olmadığından emin olabilirim.
supercat

@supercat Temelde bu: Ben sıkı tip kontrol ve kontrol istisnaları çok zor bir hayranıyım bunun mantıklı bir uzantısı. Kavramsal olarak onları çok sevmeme rağmen, kontrol edilmiş istisnaları tamamen terk ettim.
Konrad Rudolph

1
Bir ben çözecek açıklanan mekanizma, eğer ki istisnalar tasarımı ile var huysuzlaştırmak fooatma olarak belgelenmiştir barExceptionbir dosyanın sonuna okuma ve zaman fooatar bir yöntem çağırır barExceptionolsa bile foobunu beklemiyordum, çağrılar foodosyanın sonuna ulaşıldığını düşünecek ve beklenmedik bir şey olduğuna dair hiçbir ipucu olmayacak. Bu durumu, kontrol edilen istisnaların en yararlı olması gereken durum olarak değerlendiririm , ancak derleyicinin işlenmemiş kontrol edilmiş istisnalara izin vereceği tek durumdur.
supercat

@supercat: Kodun ilk yorumda ne istediğinizi yapmasının kolay bir yolu var: kodu bir try bloğuna sarın, İstisna'yı yakalayın ve İstisna'yı bir RuntimeException istisnasına sarın ve yeniden başlayın.
Warren Dew

1
@KonradRudolph supercat "belirli bir kod bloğu" olarak anılır; bloğun tanımlanması gerektiğinde, bildirim sözdizimi şişkinliği önemli ölçüde azaltmaz. Tüm işlev için bildirimde bulunacağını düşünüyorsanız, insanlar kötü bir şekilde yakalanan kontrol edilen istisnalara bakmak ve daha iyi bir yol olmadığından emin olmak yerine, bildiriye sadık kalacağı için kötü programlamayı teşvik eder. onları idare etmek için.
Warren Dew

46

Yeterince büyük bir sistemde, birçok katmanla, kontrol edilen istisna işe yaramaz çünkü zaten, istisnanın nasıl ele alınacağını ele almak için bir mimari seviye stratejisine ihtiyacınız var (bir hata bariyeri kullanın)

İşaretli istisnalar dışında hata işleme durumunuz mikro olarak yönetilir ve herhangi bir büyük sistemde dayanılmazdır.

Çoğu zaman bir hatanın "kurtarılabilir" olup olmadığını bilmezsiniz, çünkü API'nızın arayan katmanının hangi katmanda olduğunu bilmiyorsunuzdur.

Diyelim ki, bir tamsayının dize temsilini Int'ye dönüştüren bir StringToInt API'sı oluşturuyorum. API "foo" dizesiyle çağrılırsa, işaretli bir istisna atmalı mıyım? Kurtarılabilir mi? Bilmiyorum çünkü onun katmanı benim StringToInt API arayan zaten girişi onaylanmış olabilir ve bu istisna atılırsa bu bir hata veya veri bozulması ve bu katman için kurtarılamaz.

Bu durumda, API arayanı istisnayı yakalamak istemez. Sadece istisnanın "patlamasına" izin vermek istiyor. İşaretli bir istisna seçtiysem, bu arayanın yalnızca istisnayı yapay olarak yeniden anlatmak için bol miktarda işe yaramaz catch bloğu olacaktır.

Kurtarılabilir olan, çoğu zaman API'nın yazarı değil, API'nın arayanına bağlıdır. Yalnızca denetlenmeyen istisnalar bir istisnayı yakalamayı veya yok saymayı seçebildiğinden, bir API işaretli istisnaları kullanmamalıdır.



16
@alexsmail İnternet beni asla şaşırtmaz, aslında benim blogum :)
Stephane

30

Haklısın.

Kontrol edilmeyen istisnalar , sistemin hızlı bir şekilde başarısız olmasına izin vermek için kullanılır , bu iyi bir şeydir. Düzgün çalışması için yönteminizin ne beklediğini açıkça belirtmelisiniz. Bu şekilde girişi yalnızca bir kez doğrulayabilirsiniz.

Örneğin:

/**
 * @params operation - The operation to execute.
 * @throws IllegalArgumentException if the operation is "exit"
 */
 public final void execute( String operation ) {
     if( "exit".equals(operation)){
          throw new IllegalArgumentException("I told you not to...");
     }
     this.operation = operation; 
     .....  
 }
 private void secretCode(){
      // we perform the operation.
      // at this point the opreation was validated already.
      // so we don't worry that operation is "exit"
      .....  
 }

Sadece bir örnek vermek gerekirse. Mesele şu ki, sistem hızlı bir şekilde başarısız olursa, nerede ve neden başarısız olduğunu bileceksiniz. Aşağıdaki gibi bir yığın izlemesi alacaksınız:

 IllegalArgumentException: I told you not to use "exit" 
 at some.package.AClass.execute(Aclass.java:5)
 at otherPackage.Otherlass.delegateTheWork(OtherClass.java:4569)
 ar ......

Ve ne olduğunu bileceksin. "DelegateTheWork" yöntemindeki (4569 satırındaki) OtherClass, sınıfınızı "çıkış" değeriyle çağırdı, hatta olmamalıdır.

Aksi takdirde, kodunuzun her yerine doğrulamaları serpin ve bu hataya açık. Artı, bazen neyin yanlış gittiğini izlemek zordur ve saatlerce sinir bozucu hata ayıklama bekleyebilirsiniz

Aynı şey NullPointerExceptions için de geçerlidir. 15 özniteliğe sahip 700 satırlık bir sınıfınız varsa, 30 özniteliği kullanır ve bunlardan hiçbiri null olamaz. fabrika yöntemi.

 public static MyClass createInstane( Object data1, Object data2 /* etc */ ){ 
      if( data1 == null ){ throw NullPointerException( "data1 cannot be null"); }

  }


  // the rest of the methods don't validate data1 anymore.
  public void method1(){ // don't worry, nothing is null 
      ....
  }
  public void method2(){ // don't worry, nothing is null 
      ....
  }
  public void method3(){ // don't worry, nothing is null 
      ....
  }

Kontrol edilen istisnalar Programcı (siz veya iş arkadaşlarınız) her şeyi doğru yaptığında, girdiyi doğruladığında, testleri çalıştırdığında ve tüm kod mükemmel olduğunda, ancak kod kapalı olabilecek bir üçüncü taraf web hizmetine bağlandığında (veya bir dosyada) kullanışlıdır. kullandığınız harici bir işlem vb. tarafından silindi). Web hizmeti, bağlantı denenmeden önce doğrulanabilir, ancak veri aktarımı sırasında bir şeyler ters gitti.

Bu senaryoda sizin veya iş arkadaşlarınızın yardım etmek için yapabileceği hiçbir şey yoktur. Ama yine de bir şey yapmalı ve uygulamanın ölmesine ve kullanıcının gözünde kaybolmasına izin vermemelisiniz. Bunun için işaretli bir istisna kullanırsınız ve istisnayı işlersiniz, bu olduğunda ne yapabilirsiniz ?, çoğu zaman, sadece hatayı günlüğe kaydetmek, muhtemelen işinizi kaydetmek (uygulama çalışması) ve kullanıcıya bir mesaj sunmak için . (Site blabla kapalı, lütfen daha sonra tekrar deneyin vb.)

İşaretli istisna aşırı kullanılırsa (tüm yöntem imzalarına "istisna atma" ekleyerek), kodunuz çok kırılgan olacaktır, çünkü herkes bu istisnayı görmezden gelecektir (çünkü çok geneldir) ve kod kalitesi ciddi olacaktır sınırlı.

Denetlenmeyen istisnayı aşırı kullanırsanız, benzer bir şey olur. Bu kodun kullanıcıları bir şeylerin yanlış gidebileceğini bilmiyorlar, bir çok deneme {...} catch (Throwable t) görünecek.


2
İyi dedi! +1. Her zaman beni bu ayrım arayan (işaretlenmemiş) / callee (kontrol) daha açık değil şaşırtıyor ...
VonC

19

İşte benim son kuralım.
Kullanırım:

  • çağırandan kaynaklanan bir hata için yöntemimin kodundaki denetlenmeyen özel durum ( açık ve eksiksiz bir belge içerir )
  • kodumu kullanmak isteyen herkese açık yapmam gereken callee nedeniyle bir hata için kontrol istisnası

Önceki cevaba kıyasla, bu, biri veya diğeri (veya her ikisi) istisnaların kullanımı için açık bir gerekçe (üzerinde anlaşmaya veya katılmayabilir).


Bu istisnaların her ikisi için, çok genel denetlenmeyen istisna (NullPointerException gibi) dışında , benim uygulama için kendi denetlenmeyen ve denetlenen İstisnemi (burada belirtildiği gibi iyi bir uygulama ) oluşturacağım.

Örneğin, aşağıdaki bu özel işlevin amacı bir nesne yapmak (veya zaten varsa elde etmek),
yani:

  • yapmak / almak için nesnenin kapsayıcısı ZORUNLU (CALLER
    => denetlenmeyen istisna sorumluluğu ve bu çağrılan işlev için javadoc açıklamasını temizle)
  • diğer parametreler null olamaz
    (CALLER'a koymak için kodlayıcının seçimi: kodlayıcı null parametresini kontrol etmez, ancak kodlayıcı BELGEYİ YAPAR)
  • sonuç NULL OLAMAZ
    (callee kodunun sorumluluğu ve seçimi, arayan için büyük ilgi duyan seçim
    => işaretli istisna çünkü nesne oluşturulamazsa / bulunamazsa her arayanın bir karar alması GEREKİR ve karar derleme zamanında uygulanmalıdır: bu işlevi bu olasılıkla uğraşmak zorunda kalmadan kullanamazlar, yani bu kontrol edilen istisna ile).

Misal:


/**
 * Build a folder. <br />
 * Folder located under a Parent Folder (either RootFolder or an existing Folder)
 * @param aFolderName name of folder
 * @param aPVob project vob containing folder (MUST NOT BE NULL)
 * @param aParent parent folder containing folder 
 *        (MUST NOT BE NULL, MUST BE IN THE SAME PVOB than aPvob)
 * @param aComment comment for folder (MUST NOT BE NULL)
 * @return a new folder or an existing one
 * @throws CCException if any problems occurs during folder creation
 * @throws AssertionFailedException if aParent is not in the same PVob
 * @throws NullPointerException if aPVob or aParent or aComment is null
 */
static public Folder makeOrGetFolder(final String aFoldername, final Folder aParent,
    final IPVob aPVob, final Comment aComment) throws CCException {
    Folder aFolderRes = null;
    if (aPVob.equals(aParent.getPVob() == false) { 
       // UNCHECKED EXCEPTION because the caller failed to live up
       // to the documented entry criteria for this function
       Assert.isLegal(false, "parent Folder must be in the same PVob than " + aPVob); }

    final String ctcmd = "mkfolder " + aComment.getCommentOption() + 
        " -in " + getPNameFromRepoObject(aParent) + " " + aPVob.getFullName(aFolderName);

    final Status st = getCleartool().executeCmd(ctcmd);

    if (st.status || StringUtils.strictContains(st.message,"already exists.")) {
        aFolderRes = Folder.getFolder(aFolderName, aPVob);
    }
    else {
        // CHECKED EXCEPTION because the callee failed to respect his contract
        throw new CCException.Error("Unable to make/get folder '" + aFolderName + "'");
    }
    return aFolderRes;
}

19

Bu sadece istisnadan kurtulma yeteneği meselesi değil. En önemlisi, bence, arayanın istisnayı yakalamak isteyip istemediğidir.

Başka bir yerde kullanılmak üzere bir kütüphane veya uygulamanızda daha alt düzey bir katman yazarsanız, arayanın istisnanızı yakalamak (bilmek hakkında) olup olmadığını kendinize sorun. Değilse, kontrol edilmeyen bir istisna kullanın, bu yüzden ona gereksiz yere yük yüklemezsiniz.

Bu, birçok çerçeve tarafından kullanılan felsefedir. Özellikle bahar ve hazırda bekletme modları akılda tutulur - bilinen kontrol edilmiş istisnayı tam olarak kontrol edilmemiş istisnaya dönüştürürler çünkü kontrol edilen istisnalar Java'da aşırı kullanılır. Düşünebileceğim bir örnek, kontrol edilen bir istisna olan ve çoğunlukla sinir bozucu olan json.org'dan JSONException'dır - işaretlenmemelidir, ancak geliştirici bunu düşünmemişti.

Bu arada, çoğu zaman arayanın istisnaya olan ilgisi, istisnadan kurtulma yeteneği ile doğrudan ilişkilidir, ancak bu her zaman böyle değildir.


13

İşte Kontrol Edilmiş / Kontrol Edilmemiş ikileminiz için çok basit bir çözüm.

Kural 1: Kod yürütülmeden önce Denetlenmeyen Özel Durum'u test edilebilir bir koşul olarak düşünün. Örneğin…

x.doSomething(); // the code throws a NullPointerException

burada x boştur ...… kodun muhtemelen aşağıdakilere sahip olması gerekir…

if (x==null)
{
    //do something below to make sure when x.doSomething() is executed, it won’t throw a NullPointerException.
    x = new X();
}
x.doSomething();

Kural 2: İşaretli İstisna'yı, kod yürütülürken oluşabilecek test edilemeyen bir koşul olarak düşünün.

Socket s = new Socket(“google.com”, 80);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

… Yukarıdaki örnekte, URL (google.com) DNS sunucusunun kapalı olması nedeniyle kullanılamayabilir. Şu anda bile DNS sunucusu çalışıyor ve 'google.com' adını bir IP adresine çözmüş, bağlantı google.com'a yapılmışsa, her andan sonra ağ kapanabilir. Akışlara okuma ve yazma işleminden önce ağı her zaman test edemezsiniz.

Bir sorun olup olmadığını bilmeden önce kodun çalıştırılması gereken zamanlar vardır. Geliştiricileri kodlarını Checked Exception aracılığıyla bu durumlarla başa çıkmaya zorlayacak şekilde yazmaya zorlayarak, şapkamı bu konsepti icat eden Java'nın yaratıcısına yatırmam gerekiyor.

Genel olarak, Java'daki hemen hemen tüm API'ler yukarıdaki 2 kurala uyar. Bir dosyaya yazmaya çalışırsanız, yazma işlemi tamamlanmadan önce disk dolar. Diğer işlemlerin diskin dolmasına neden olmuş olabilir. Bu durumu test etmenin bir yolu yoktur. Herhangi bir zamanda donanımı kullanmanın başarısız olabileceği donanımla etkileşim kuranlar için, Denetlenen İstisnalar bu soruna zarif bir çözüm gibi görünmektedir.

Bunun gri bir alanı var. Birçok teste ihtiyaç duyulması durumunda (&& ve || ifadesi çok fazla ise akıllara durgunluk veren bir düşünce), atılan istisna bir CheckedException olacaktır, çünkü doğru olamayacak kadar çok acı çekmektedir - bu sorunu söyleyemezsiniz. bir programlama hatasıdır. 10'dan az test varsa (örn. 'İf (x == null)'), programcı hatası bir UncheckedException olmalıdır.

Dil tercümanlarıyla uğraşırken işler ilginçleşir. Yukarıdaki kurallara göre, bir Sözdizimi Hatası İşaretli veya Denetlenmemiş Özel Durum olarak mı değerlendirilmelidir? Dilin sözdizimi yürütülmeden önce test edilebilirse, bunun bir UncheckedException olması gerektiğini savunuyorum. Dil test edilemiyorsa - montaj kodunun kişisel bir bilgisayarda nasıl çalıştığına benzer şekilde, Sözdizimi Hatası bir Denetlenen Özel Durum olmalıdır.

Yukarıdaki 2 kural, muhtemelen seçim yapabileceğiniz endişenizin% 90'ını kaldıracaktır. Kuralları özetlemek için, şu kalıbı izleyin… 1) çalıştırılacak kodun düzgün çalışması için yürütülmeden önce test edilebilirse ve bir İstisna oluşursa - bir programcı hatası olarak, İstisna bir UncheckedException (RuntimeException alt sınıfı olmalıdır) ). 2) çalıştırılacak kodun düzgün çalışması için yürütülmeden önce test edilemiyorsa, İstisna bir Kontrol Edilmiş İstisna (İstisna alt sınıfı) olmalıdır.


9

İşaretli veya işaretsiz bir istisna diyebilirsiniz; ancak, her iki istisna türü programcı tarafından yakalanabilir, bu nedenle en iyi yanıt şudur: Tüm istisnalarınızı kontrolsüz olarak yazın ve bunları belgeleyin. Bu şekilde API'nızı kullanan geliştirici, bu istisnayı yakalamak ve bir şeyler yapmak isteyip istemediğini seçebilir. İşaretli istisnalar herkesin zamanının tam bir israfıdır ve kodunuzu bakmak için şok edici bir kabus yapar. Uygun birim testi daha sonra yakalamak ve bir şeyler yapmak zorunda kalabileceğiniz istisnaları ortaya çıkaracaktır.


1
+1 Ünite testlerinin sorunu çözmenin daha iyi bir yolu olabileceğini belirtmek için, kontrol edilen istisnaların çözmesi amaçlanmıştır.
Keith Pinson

Birim testi için +1. İşaretli / Denetlenmemiş istisnaları kullanmanın kod kalitesi üzerinde çok az etkisi vardır. Bu nedenle, kontrol edilen istisnalar kullanılırsa, daha iyi kod kalitesiyle sonuçlanacağı argümanı tam bir sahte argüman!
user1697575 18:13

7

İşaretli Kural Dışı Durum : İstemci bir kural dışı durumdan kurtarabilirse ve devam etmek istiyorsa, kontrol edilen kural dışı durumu kullanın.

Denetlenmeyen Özel Durum : İstemci özel durumdan sonra herhangi bir şey yapamazsa, denetlenmeyen özel durumu yükseltin.

Örnek: Bir yöntem A () 'de aritmetik işlem yapmanız ve A ()' dan elde edilen çıktıya dayanarak, başka bir işlem yapmanız gerekir. Çıktı, çalışma süresi sırasında beklemediğiniz A () yönteminden null olursa, Çalışma zamanı istisnası olan Null pointer Exception'ı atmanız beklenir.

Buraya bakın


2

Özellikle API tasarlarken, kural olarak denetlenmeyen istisnalar tercihini kabul ediyorum. Arayan her zaman belgelenmiş, kontrol edilmemiş bir istisnayı yakalamayı seçebilir. Arayanı gereksiz yere zorlamıyorsunuz.

Kontrol edilmiş istisnaları, uygulama ayrıntısı olarak alt düzeyde yararlı buluyorum. Genellikle belirli bir hata "dönüş kodu" nu yönetmekten daha iyi bir kontrol mekanizması akışı gibi görünür. Bazen düşük seviyeli kod değişikliği için bir fikrin etkisini görmeye de yardımcı olabilir ... akış aşağısında kontrol edilen bir istisna beyan edin ve kimlerin ayarlaması gerektiğini görün. Bu son nokta, çok fazla genel varsa geçerli değildir: catch (İstisna e) veya genellikle çok iyi düşünülmeyen İstisnaları atar .


2

İşte uzun yıllar süren geliştirme deneyiminden sonra sahip olduğum düşüncemi paylaşmak istiyorum:

  1. Kontrol edilmiş istisna. Bu iş kullanım durumu veya çağrı akışının bir parçasıdır, bu beklediğimiz veya beklemediğimiz uygulama mantığının bir parçasıdır. Örneğin bağlantı reddedildi, koşul yerine getirilmedi vb. Bunu halletmeli ve ne olduğunu ve sonra ne yapacağını belirten talimatları kullanıcıya göstermeliyiz (daha sonra tekrar deneyin vb.). Genellikle işleme sonrası istisna veya "kullanıcı" istisnası diyorum.

  2. İşaretlenmeyen istisna. Bu, programlama istisnasının bir parçasıdır, yazılım kodu programlamasında bazı hatalar (hata, hata) ve programcıların belgelere göre API'yi nasıl kullanmaları gerektiğini yansıtır. Harici bir lib / framework dokümanı, NPE veya IllegalArgumentException atılacağı için belirli bir aralıkta veri almayı beklediğini söylüyorsa, programcı bunu beklemeli ve API'yi belgelere göre doğru şekilde kullanmalıdır. Aksi takdirde istisna atılır. Genellikle ön işleme istisnası veya "doğrulama" istisnası diyorum.

Hedef kitleye göre. Şimdi hedef kitle veya bir grup insan hakkında, istisnaların tasarlandığından bahsedelim (benim düşünceme göre):

  1. Kontrol edilmiş istisna. Hedef kitle kullanıcılar / müşterilerdir.
  2. İşaretlenmeyen istisna. Hedef kitle geliştiricilerdir. Başka bir deyişle, işaretlenmeyen istisna yalnızca geliştiriciler için tasarlanmıştır.

Uygulama geliştirme yaşam döngüsü aşaması ile.

  1. Kontrol edilen istisna, bir uygulamanın istisnai durumları ele aldığı normal ve beklenen mekanizma olarak tüm üretim yaşam döngüsü boyunca var olacak şekilde tasarlanmıştır.
  2. Denetlenmeyen istisna, yalnızca uygulama geliştirme / test yaşam döngüsü sırasında var olacak şekilde tasarlanmıştır; bunların tümü bu süre içinde düzeltilmeli ve bir uygulama zaten üretimde çalışırken atılmamalıdır.

Çerçevelerin genellikle denetlenmeyen istisnalar kullanmasının nedeni (örneğin Bahar), çerçevenin uygulamanızın iş mantığını belirleyememesidir, bu, geliştiricilerin kendi mantığını yakalamaları ve tasarlamalarıdır.


2

Bu iki istisna türünü, programcı hatası olup olmamasına göre ayırt etmeliyiz.

  • Bir hata programcı hatasıysa, Kontrol Edilmemiş İstisna olmalıdır . Örneğin: SQLException / IOException / NullPointerException. Bu istisnalar programlama hatalarıdır. Programcı tarafından ele alınmalıdır. JDBC API'sinde, SQLException İşaretli İstisnası, İlkbaharda JDBCTemplate, Denetlenmeyen Bir İstisna'dır.
  • Bir hata bir programcı hatası değilse ve nedeni harici bir durumdan geliyorsa, bir Denetlenen İstisna olmalıdır. Örneğin: dosya silinirse veya başka biri tarafından dosya izni değiştirilirse kurtarılmalıdır.

FileNotFoundException, ince farkları anlamak için iyi bir örnektir. Dosyanın bulunamaması durumunda FileNotFoundException atılır. Bu istisnanın iki nedeni vardır. Dosya yolu geliştirici tarafından tanımlanırsa veya GUI aracılığıyla son kullanıcıdan alınırsa, Denetlenmeyen Özel Durum olmalıdır. Dosya başka biri tarafından silinirse, İşaretli İstisna olmalıdır.

İşaretli İstisna iki şekilde ele alınabilir. Bunlar try-catch veya istisnayı yayarlar. Özel durumun yayılması durumunda, özel durum işleme nedeniyle çağrı yığınındaki tüm yöntemler sıkıca bağlanır . Bu nedenle, Checked Exception'ı dikkatle kullanmalıyız.

Katmanlı bir kurumsal sistem geliştirmeniz durumunda, atmak için çoğunlukla denetlenmeyen istisna seçmeniz gerekir, ancak hiçbir şey yapamayacağınız durumda kontrol edilen istisnayı kullanmayı unutmayın.


1

İşaretli istisnalar, arayan kişiye bilgi vermek istediğiniz kurtarılabilir durumlar için yararlıdır (örn. Yetersiz izinler, dosya bulunamadı, vb.).

Kontrol edilmeyen istisnalar, kullanıcıyı veya programcıyı çalışma sırasında ciddi hatalar veya beklenmedik durumlar hakkında bilgilendirmek için nadiren kullanılır. Başkaları tarafından kullanılacak kod veya kitaplıklar yazıyorsanız bunları atmayın, çünkü bunlar derleyicinizin yakalanmasına veya bildirilmesine zorlamadığı için yazılımınızın denetlenmeyen istisnalar atmasını beklemiyor olabilir.


"Kontrol edilmeyen istisnalar nadiren kullanılır, eğer hiç değilse" aslında bunun tersi olmalı! Uygulama istisnaları hiyerarşinizi tasarlarken varsayılan olarak işaretlenmeyen istisnalar kullanın. Geliştiricilerin istisnayı ne zaman ele almak istediklerine karar vermelerine izin verin (örneğin, nasıl ele alınacaklarını bilmiyorlarsa catch blokları koymak veya atış cümleleri koymak zorunda değildirler).
user1697575

1

Bir istisna daha az olası olsa ve bunu yakaladıktan sonra bile devam edebiliriz ve bu istisnayı önlemek için hiçbir şey yapamayız, o zaman kontrol edilen istisnayı kullanabiliriz.

Belirli bir istisna oluştuğunda ve bu istisnanın beklendiği, ancak kesin olmadığı zaman anlamlı bir şey yapmak istediğimizde, kontrol edilen istisnayı kullanabiliriz.

Farklı katmanlarda gezinme istisnası olduğunda, her katmanda yakalamamız gerekmez, bu durumda çalışma zamanı istisnasını kullanabilir veya istisnayı denetlenmeyen istisna olarak kullanabiliriz.

Çalışma zamanı istisnası, istisna olma olasılığı en yüksek olduğunda kullanılır, daha ileri gidemez ve hiçbir şey kurtarılamaz. Bu durumda, bu istisna ile ilgili önlemler alabiliriz. EX: NUllPointerException, ArrayOutofBoundsException. Bunlar daha olasıdır. Bu senaryoda, böyle bir istisnayı önlemek için kodlama yaparken önlemler alabiliriz. Aksi takdirde her yerde try catch blokları yazmamız gerekecek.

Daha genel istisnalar yapılabilir Kontrolsüz, daha az genel kontrol edilir.


1

Sanırım birkaç sorudan muafiyetleri düşünebiliriz:

neden istisna olur? Bu olduğunda ne yapabiliriz

yanlışlıkla, bir hata. null nesnesi yöntemi gibi denir.

String name = null;
... // some logics
System.out.print(name.length()); // name is still null here

Bu tür istisnalar test sırasında düzeltilmelidir. Aksi takdirde, üretimi bozar ve derhal düzeltilmesi gereken çok yüksek bir hatayla karşılaşırsınız. Bu tür istisnaların kontrol edilmesi gerekmez.

harici giriş yoluyla , harici servis çıkışını kontrol edemez veya güvenemezsiniz.

String name = ExternalService.getName(); // return null
System.out.print(name.length());    // name is null here

Burada, null olduğunda devam etmek istiyorsanız adın null olup olmadığını kontrol etmeniz gerekebilir, aksi takdirde, yalnız bırakabilirsiniz ve burada duracak ve arayan kişiye çalışma zamanı istisnası verecektir. Bu tür istisnaların kontrol edilmesi gerekmez.

harici çalışma zamanı istisnasıyla , harici hizmeti kontrol edemez veya güvenemezsiniz.

Burada, gerçekleştiğinde devam etmek istiyorsanız, ExternalService'teki tüm istisnaları yakalamanız gerekebilir, aksi takdirde, tek başına bırakabilirsiniz ve burada durur ve arayan kişiye çalışma zamanı istisnasını verir.

harici olarak işaretlenen istisna dışında , harici hizmeti kontrol edemez veya güvenemezsiniz.

Burada, gerçekleştiğinde devam etmek istiyorsanız, ExternalService'teki tüm istisnaları yakalamanız gerekebilir, aksi takdirde, tek başına bırakabilirsiniz ve burada durur ve arayan kişiye çalışma zamanı istisnasını verir.

Bu durumda, ExternalService'te ne tür bir istisna olduğunu bilmemiz gerekir mi? Değişir:

  1. bazı istisnaları kaldırabiliyorsanız, bunları yakalamanız ve işlemeniz gerekir. Diğerleri için onları kabarcıklayın.

  2. belirli yürütme günlüğü veya kullanıcıya yanıt gerekiyorsa, onları yakalayabilirsiniz. Diğerleri için onları kabarcıklayın.


0

Uygulama İstisnası bildirilirken, Kontrol Edilmemiş İstisna yani RuntimeException alt sınıfı olması gerektiğini düşünüyorum. Bunun nedeni, uygulama kodunu try-catch ile karıştırmayacak ve yönteme bildirim atayacaktır. Uygulamanız, yine de ele alınması gereken özel durumları atan Java Api kullanıyorsa. Diğer durumlarda, uygulama denetlenmeyen istisna atabilir. Uygulama arayanının hala denetlenmeyen özel durumu işlemesi gerekiyorsa, bu yapılabilir.


-12

Kullandığım kural: asla denetlenmeyen istisnalar kullanmayın! (veya etrafında bir yol göremediğinizde)

Kitaplığınızı kullanan geliştiricinin veya kitaplığınızı / uygulamanızı kullanan son kullanıcının bakış açısından, ele alınmayan bir istisna nedeniyle çöken bir uygulama ile karşılaşmak gerçekten berbat. Ve bir catch-all'a güvenmek de iyi değil.

Bu şekilde, son kullanıcıya uygulama tamamen kaybolmak yerine bir hata mesajı verilebilir.


1
Çoğu denetlenmeyen istisna için neyin yanlış olduğunu düşündüğünüzü açıklamıyorsunuz.
Matthew Flaschen

Tartışmasız cevabınıza tamamen katılmayın: "asla kontrol edilmeyen istisnalar kullanmayın"
user1697575
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.