Java'da, denetlenen istisnalar ne işe yarar? [kapalı]


14

Java'nın kontrol edilen istisnaları yıllar boyunca bazı kötü baskılara maruz kaldı. Söyleyen bir işaret, kelimenin tam anlamıyla onlara sahip olan tek dildir (Groovy ve Scala gibi diğer JVM dilleri bile değil). Spring ve Hibernate gibi önde gelen Java kitaplıkları da bunları kullanmaz.

Şahsen onlar için bir kullanım buldum ( katmanlar arasındaki iş mantığında ), ama aksi takdirde oldukça anti-kontrol istisnalarım.

Farkında olmadığım başka kullanımlar var mı?


Tüm Java çekirdek kitaplıkları, denetlenen özel durumları oldukça kapsamlı bir şekilde kullanır.
Joonas Pulakka

3
@Kaya biliyorum, ve bu bir acı!
Brad Cupit

Yanıtlar:


22

Her şeyden önce, diğer programlama paradigmaları gibi, iyi çalışması için bunu doğru yapmanız gerekir.

İçin beni kontrol istisnalar avantajı ZATEN ben makul beklenen ortak ne sorunlar benim için karar verdik Java çalışma zamanı kitaplığının yazarları de idare edebilmek için olmasıdır çağıran bir üst düzey yakalama basılı-karşıt olarak (nokta die block) ve bu sorunları nasıl çözeceğinizi olabildiğince erken düşünün.

Denetimli istisnaları seviyorum çünkü onlar beni mümkün olduğunca erken hata kurtarma hakkında düşünmeye zorlayarak kodumu daha sağlam hale.

İçin, daha kesin olmak gerekirse benim dayanan çok erken söyleyerek aksine sürecinde garip köşe durumlarda dikkate almak beni zorlar olarak bu daha sağlam kodumu yapar "dosyası henüz mevcut değilse Hata benim kod işlemez" üretimde bir hata, daha sonra işlemek için kodunuzu yeniden işlemeniz gerekir. Mevcut koda hata işleme eklemek, yalnızca en baştan yapmak yerine bakıma ulaştığında önemsiz bir görev olabilir ve bu nedenle pahalıdır.

Kayıp dosya ölümcül bir şey olduğunu olabilir ve alevler içinde çökmesine programı neden olmalı, ama sonra sen bu kararı ile yapmak

} catch (FileNotFoundException e) {
  throw new RuntimeException("Important file not present", e);
}

Bu aynı zamanda çok önemli bir yan etki gösterir. Bir istisnayı sararsanız , yığın izlemesine giden bir açıklama ekleyebilirsiniz ! Bu son derece güçlüdür, çünkü örneğin eksik olan dosyanın adı veya bu yönteme veya diğer tanılama bilgilerine iletilen parametreler hakkında bilgi ekleyebilirsiniz ve bu bilgiler doğrudan yığın izinde bulunur. bir program çöktüğünde alın.

İnsanlar "bunu çoğaltmak için hata ayıklayıcıda çalıştırabiliriz" diyebilir, ancak çok sık üretim hatalarının daha sonra yeniden üretilemediğini ve esasen işinizin tehlikede olduğu çok kötü durumlar dışında üretimde hata ayıklayıcıları çalıştıramayacağımızı fark ettim .

Yığın izinizde ne kadar fazla bilgi olursa o kadar iyidir. İşaretli istisnalar, bu bilgileri oraya ve erken almama yardımcı oluyor.


EDIT: Bu kütüphane tasarımcıları için de geçerli. Günlük bazda kullandığım bir kütüphane, kullanımı daha az sıkıcı hale getirecek şekilde çok daha iyi tasarlanmış olabilecek çok sayıda kontrol edilmiş istisna içeriyor.


+1. Spring'in tasarımcıları, birçok Hibernate istisnasını kontrol edilmeyen istisnalara çevirmek için iyi bir iş çıkardı.
Fil

Bilginize: Frank Sommers bu sözü iplik hataya dayanıklı yazılım genellikle çok aynı mekanizma itimat söyledi. Belki cevabınızı geri kazanılabilir davaya ve ölümcül davaya ayırabilirsiniz.
rwong

@rwong, aklınızdakileri daha ayrıntılı açıklar mısınız?

11

Kontrol edilen istisnaların uygulamada ne olduğunu açıklayan iki iyi cevabınız var. (Her ikisine de +1.) Ancak teoride amaçlandıklarını incelemek de faydalı olacaktır, çünkü niyet aslında değerlidir.

İşaretli istisnalar aslında dili daha güvenli hale getirmeyi amaçlamaktadır. Tamsayı çarpımı gibi basit bir yöntem düşünün. Bu yöntemin sonuç türünün bir tamsayı olacağını düşünebilirsiniz, ancak, kesin olarak söylemek gerekirse, sonuç bir tamsayı veya bir taşma istisnasıdır. Tamsayı sonucunu, yöntemin dönüş türü olarak tek başına değerlendirmek, işlevin tüm aralığını ifade etmez.

Bu açıdan bakıldığında, kontrol edilen istisnaların diğer dillere ulaşmadığını söylemek kesinlikle doğru değildir. Java'nın kullandığı formu almamışlar. Haskell uygulamalarında, fonksiyonun başarılı ve başarısız tamamlanmasını ayırt etmek için cebirsel veri türlerinin kullanılması yaygındır. Her ne kadar bu bir istisna olmasa da, niyet kontrol edilen bir istisna ile hemen hemen aynıdır; API tüketicisini, başarısız olan durumda başarılı olanlarla başa çıkmaya zorlamak için tasarlanmış bir API'dır. Örneğin:

data Foo a =
     Success a
   | DidNotWorkBecauseOfA
   | DidNotWorkBecauseOfB

Bu, programcıya işlevin başarı dışında iki olası sonucu daha olduğunu söyler.


Tip güvenliği hakkında kontrol edilen istisnalar için +1. Bu fikri daha önce hiç duymamıştım ama bu çok mantıklı.
Ixrec

11

IMO, kontrol edilen istisnalar, oldukça iyi bir fikrin ne olabileceğinin kusurlu bir uygulamasıdır (tamamen farklı koşullar altında - ancak mevcut koşullar altında gerçekten iyi bir fikir bile değildir).

İyi fikir, derleyicinin bir programın atma potansiyeli olan tüm istisnaların yakalanacağını doğrulamasının iyi olacağıdır. Kusurlu uygulama, bunu yapmak için Java, herhangi bir sınıfın kontrol edilen bir istisna attığı bildirilen herhangi bir şeyi çağırdığı durumlarda doğrudan istisna ile uğraşmaya zorlamasıdır. İstisna işlemenin en temel fikirlerinden (ve avantajlarından) biri, bir hata durumunda, belirli bir hata ile ilgisi olmayan ara kod katmanlarının varlığını tamamen görmezden gelmesine izin vermesidir. İşaretli istisnalar (Java'da uygulandığı gibi) buna izin vermez, bu nedenle istisna işlemenin başlaması için büyük bir (birincil?) Avantajı yok eder.

Teorik olarak, kontrol edilmiş istisnaları sadece program çapında uygulayarak yararlı hale getirebilirlerdi - yani programı "oluştururken", programdaki tüm kontrol yollarından bir ağaç oluştururlar. Ağaçtaki çeşitli düğümlere 1) oluşturabilecekleri istisnalar ve 2) yakalayabilecekleri istisnalar eklenebilir. Programın doğru olduğundan emin olmak için, ağaçta herhangi bir seviyede atılan her istisnanın ağaçta daha yüksek bir seviyede yakalandığını doğrulayarak ağacı yürürsünüz.

Bunu yapmamalarının nedeni (her neyse, sanırım) bunu yapmanın çok zor olacağıdır - aslında, herkesin bunu son derece basit (sınırda "oyuncaktan başka bir şey için yapabilen bir inşa sistemi yazdığından şüpheliyim ") diller / sistemler. Java için, dinamik sınıf yükleme gibi şeyler, diğer birçok durumdan daha da zor hale getirir. Daha da kötüsü, (C gibi bir şeyden farklı olarak) Java (en azından normal olarak) statik olarak bir yürütülebilir dosyaya derlenmez / bağlanmaz. Bu, sistemdeki hiçbir şeyin , son kullanıcı aslında programı çalıştırmak için programı yüklemeye başlayana kadar bu tür bir yaptırımı yapmaya çalışmak için küresel bir bilince sahip olmadığı anlamına gelir .

Bu noktada yaptırım uygulamak birkaç nedenden dolayı pratik değildir. Her şeyden önce, en iyi ihtimalle bile, Java ile ilgili en büyük, en yaygın şikayetlerden biri olan başlangıç ​​zamanlarını uzatırdı. İkincisi, çok iyi yapmak için, sorunu bir programcının düzeltmesi için yeterince erken tespit etmeniz gerekir. Kullanıcı programı yüklerken, çok iyi yapmak için çok geç - bu noktada tek seçeneğiniz sorunu göz ardı etmek veya programı yüklemeyi / çalıştırmayı reddetmek, bir istisna olabilir yakalanmadı.

Olduğu gibi, kontrol edilen istisnalar işe yaramazdan daha kötüdür, ancak kontrol edilen istisnalar için alternatif tasarımlar daha da kötüdür. Kontrol edilen istisnalar için temel fikir iyi bir fikir gibi görünse de, gerçekten çok iyi değil ve Java için özellikle zayıf bir uyum. C ++ gibi bir şey için, normalde yansıma / dinamik sınıf yüklemesi gibi bir şey olmadan tam bir yürütülebilir dosyaya derlenir / bağlanır, biraz daha şansa sahip olursunuz (yine de, açıkçası, hatta aynı karışıklık olmadan onları doğru bir şekilde uygularsınız) şu anda Java'da hala büyük olasılıkla mevcut durumun ötesinde olabilir).


İstisnayı doğrudan ele almakla ilgili ilk ifadeniz zaten yanlıştır; basitçe bir throws ifadesi ekleyebilirsiniz ve bu throws ifadesi bir üst türden olabilir. Ayrıca, gerçekten ele almanız gerektiğini düşünmüyorsanız, bunun yerine bir RuntimeException öğesine dönüştürebilirsiniz. IDE'ler genellikle her iki görevde de size yardımcı olur.
Maarten Bodewes

2
@owlstead: Teşekkürler - Muhtemelen oradaki ifadelere daha dikkat etmeliydim. Asıl nokta, istisnayı yakalamak zorunda olduğunuz kadar fazla değildi, çünkü her orta seviye kodun içinden akabilecek her istisnanın farkında olması gerekiyordu. Geri kalanlara gelince: Kodunuzu karıştırmayı hızlı ve kolay hale getiren bir araca sahip olmak, kodun karışıklık yaratması gerçeğini değiştirmez.
Jerry Coffin

İşaretli istisnalar yönelik olduğunu şarta - farklı olarak, başarıya daha öngörülebilir ve geri kazanılabilir sonuçların diğer arızaları öngörülemeyen alt düzey / veya sistem problemleri -. FileNotFound veya JDBC bağlantısı açılırken hata oluştu. Ne yazık ki, Java kitaplığı tasarımcıları tamamen hata yaptı ve diğer tüm IO ve SQL istisnalarını da 'işaretli' sınıfa atadı; bunlar neredeyse tamamen kurtarılamaz olmasına rağmen. literatejava.com/exceptions/…
Thomas W

@owlstead: İşaretli istisnalar, yalnızca çağrı kodunun beklediği durumlarda atılırsa çağrı yığınının ara katmanları boyunca kabarcık oluşturmalıdır . IMHO, arayanların onları yakalaması veya beklenip beklenmediğini belirtmesi durumunda, kontrol edilen istisnalar iyi bir şey olurdu ; beklenmeyen istisnalar otomatik olarak UnexpectedExceptiontüretilmiş bir türe sarılmalıdır RuntimeException. "Atar" ve "beklemez" in çelişki olmadığını unutmayın; eğer fooatar BozExceptionve ararsa bar, bu baratmayı beklediği anlamına gelmez BozException.
supercat

10

Can sıkıcı programcılar ve istisna yutmayı teşvik etmek için gerçekten çok iyi. İstisnaların yarısı, hataları ele almanın varsayılan bir yoluna sahip olmanız ve işleyemeyeceğiniz hata koşullarını açıkça yaymak zorunda kalmamanızdır. (Aklı varsayılanı, hatayı kodunuzun hiçbir yerinde asla ele almazsanız, bunun gerçekleşemeyeceğini etkili bir şekilde iddia etmiş olursunuz ve yanılıyorsanız bir aklı çıkış ve yığın iziyle bırakılırsınız.) İstisnaların yenilgisini kontrol ettiniz. bu. C'deki hataları açıkça yaymak zorunda gibi hissediyorlar.


4
Kolay düzeltme: throws FileNotFoundException. Sabit düzeltme:catch (FileNotFoundException e) { throw RuntimeException(e); }
Thomas Eding

5

Kontrol edilen istisnaların biraz başarısız bir deneme olduğunu söylemek doğru olur. Yanlış gittikleri yerler katmanlaşmayı kırdılar:

  • Modül A, Modül B'nin üzerine inşa edilebilir;
  • Modül B, Modül C'nin üzerine inşa edilmiş olabilir.
  • C modülü bir hatanın nasıl tanımlanacağını bilebilir ve
  • Modül A, hatanın nasıl ele alınacağını biliyor olabilir.

İlgililerin hoş ayrımı bozuldu, çünkü şimdi A ve C ile sınırlı olabilecek hataların bilgisinin B'ye dağılması gerekiyor.

Bir yoktur güzel tartışma Vikipedi'de kontrol istisnalar.

Bruce Eckel'in de güzel bir makalesi var. İşte bir teklif:

[T] daha rastgele kurallar programcı üzerine kazık, eldeki sorunu çözmekle ilgisi olmayan kurallar, programcı daha yavaş üretebilir. Ve bu doğrusal bir faktör değil, üstel bir faktör gibi görünüyor

Tüm yöntemler throwsşartname yan tümcesi varsa, o zaman bazı güzel optimizasyonlar olabilir , C ++ durumunda inanıyorum . Yine de Java'nın bu avantajlara sahip olabileceğine inanmıyorum, çünkü RuntimeExceptionskontrol edilmedi. Modern bir JIT, kodu zaten iyi bir şekilde optimize edebilmelidir.

AspectJ'nin hoş bir özelliği istisna yumuşatmadır: İşaretli istisnaları özellikle katmanlamayı geliştirmek için kontrol edilmemiş istisnalara dönüştürebilirsiniz.

Belki de Java'nın bu sorunu kontrol ettiği zaman tüm bu sorunlardan geçmesi ironiktir null, ki bu çok daha değerli olabilir .


haha, null şeyi kontrol etmedikleri bir karar olarak düşünmedim ... Ama sonunda nulls'ın çağrıldığı yöntemlere izin veren Objective-C'de çalıştıktan sonra doğuştan gelen bir sorun OLMADIĞINI anladım.
Dan Rosenstark

3
null denetimi çok daha büyük bir acıdır - HER ZAMAN kontrol etmeniz gerekir - artı nedeninin iyi bilinen bir istisnanın nedenini söylemez.

5

İstisnaları severim.

Bununla birlikte, sürekli olarak yanlış kullanımlarından şaşkınım.

  1. Akış işleme için bunları kullanmayın. Bir şey yapmaya çalışan ve başka bir şey yapmak için tetikleyici olarak bir istisna kullanan kod istemezsiniz, çünkü istisnalar yaratılması ve bellek vb. Kullanması gereken nesnelerdir, çünkü sadece bazılarını yazmak için rahatsız edilemezsiniz. arama yapmadan önce if () türünü kontrol edin. Bu sadece tembel ve görkemli İstisnaya kötü bir isim veriyor.

  2. Onları yutma. Hiç. Herhangi bir koşul altında. Mutlak bir minimum olarak, bir istisna olduğunu belirtmek için günlük dosyanıza bir şey yapıştırırsınız. İstisnaları yutan kodla yolunuzu takip etmeye çalışmak bir kabustur. Yine, kudretli İstisnayı itibarsızlaştırmak için istisna-yutkunuculara lanet!

  3. OO şapkanızla İstisnalar uygulayın. Anlamlı hiyerarşilerle kendi İstisna nesnelerinizi oluşturun. İş mantığınızı ve istisnalarınızı el ele verin. Bir sistemin yeni bir alanına başlarsam kodlamanın yarım saat içinde İstisna alt sınıfına ihtiyaç duyduğumu bulurdum, bu yüzden bu günlerde İstisna sınıflarını yazarak başlıyorum.

  4. 'Çerçeveli' kod bitleri yazıyorsanız, uygun olduğunda kendi yeni İstisnalarınızı atmak için tüm başlangıç ​​arayüzlerinizin yazıldığından emin olun ... ve kodlayıcılarınızın kodları ne zaman yapılacağı konusunda örnek kodların olduğundan emin olun ancak bir IOException oluşturur, yazdıkları arayüz 'ReportingApplicationException' değerini atmak ister.

İstisnaların sizin için nasıl işe yarayacağından bahsettikten sonra asla geriye bakmayacaksınız.


2
İyi talimatlar için +1. Ayrıca, uygun olduğunda, initCauseistisnayı buna neden olan istisna ile kullanın veya başlatın. Örnek: Yalnızca yazma başarısız olursa bir istisna gerektiren bir G / Ç yardımcı programınız vardır. Ancak, bir yazmanın başarısız olmasının birden fazla nedeni vardır (erişim, yazma hatası vb.)
Michael K

3
Kaba olmak istemiyorum ama bunun CHECKED istisnaları ile ne ilgisi var? :)
palto

İşaretli istisnalar kendi hiyerarşinizi yazmak için yeniden yazılabilir .
Maarten Bodewes

4

İşaretli istisnalar da ADA'dadır.

(Uyarı, bu gönderide karşılaşabileceğiniz güçlü inançlar içeriyor.)

Programcılar onlardan hoşlanmıyor ve şikayet ediyor veya istisna yutma kodu yazıyor.

İşaretli istisnalar var çünkü işler sadece başarısız olamaz, bir hata modu / etki analizi yapabilir ve bunu önceden belirleyebilirsiniz.

Dosya okumaları başarısız olabilir. RPC çağrıları başarısız olabilir. Ağ GÇ başarısız olabilir. Veriler ayrıştırıldığında yanlış biçimlendirilebilir.

Kod için "mutlu yol" kolaydır.

Üniversitede harika "mutlu yol" kodu yazabilecek bir adam tanıyordum. Son vakaların hiçbiri işe yaramadı. Bu günlerde açık kaynak kodlu bir şirket için Python yapıyor. Dedi Nuff.

İşaretli istisnaları işlemek istemiyorsanız, gerçekten söylediğiniz şey

While I'm writing this code, I don't want to consider obvious failure modes.

The User will just have to like the program crashing or doing weird things.

But that's okay with me because 

I'm so much more important than the people who will have to use the software

in the real, messy, error-prone world.

After all, I write the code once, you use it all day long.

Bu nedenle, kontrol edilen istisnalar programcılar tarafından sevilmeyecek, çünkü daha fazla iş anlamına geliyor.

Tabii ki, diğer insanlar bu işin yapılmasını istemiş olabilirler.

Dosya sunucusu başarısız olsa / USB çubuğu ölse bile doğru cevabı istemiş olabilirler.

Programlama topluluğunda, işiniz yazılım yazmak olduğunda hayatınızı kolaylaştıran, keyif aldığınız bir programlama dili kullanmanız gerektiği garip bir inançtır. İşiniz birinin problemini çözmektir, programlı Jazz doğaçlama yapmanıza izin vermez.

Amatör bir programcıysanız (para için programlama yapmıyorsanız), C # veya başka bir dilde kontrol edilmiş istisnalar olmadan programlamaktan çekinmeyin. Heck, Logodaki orta adamı ve programı kesin. Kaplumbağa ile yere güzel desenler çizebilirsiniz.


6
Güzel rant var.
Adam Lear

2
+1 "Son vakaların hiçbiri işe yaramadı. Bu günlerde açık kaynaklı bir şirket için Python yapıyor. Nuff dedi." Klasik
NimChimpsky

1
@palto: Java sizi kolay olmayan yolu düşünmeye zorlar . Bu büyük fark. C # için "İstisna belgelenmiştir" diyebilir ve ellerinizi yıkayabilirsiniz. Ancak programcılar hataya açıktır. Bir şeyleri unutuyorlar. Kod yazdığımda, bir derleyicinin bana bildirebileceği çatlakları% 100 hatırlatmak istiyorum.
Thomas Eding

2
@ThomasEding Java, yöntemin çağrıldığı kural dışı durumu ele almaya zorlar. Aslında arama kodunda bu konuda bir şeyler yapmak istiyorum ve genellikle benim uygulama hata işleme katmanı istisna kabarcık istiyorum. Sonra bir Çalışma Zamanı istisnasında istisna tamamlayarak ya da kendi istisna oluşturmak zorunda bunu düzeltmek zorunda. Tembel programcıların üçüncü bir seçeneği var: umursamadığım için görmezden gel. Bu şekilde kimse hata olduğunu bilmiyor ve yazılımda gerçekten garip hatalar var. Bu üçüncüsü kontrol edilmeyen istisnalarla gerçekleşmez.
palto

3
@ThomasEding Uygulamanın her katmanına gereksiz yere uygulama ayrıntılarını gösteren yukarıdaki her şeyin arayüzünü değiştirecek bir işlem. Bunu sadece istisna kurtarmak istediğiniz bir şeyse ve arayüzde mantıklıysa yapabilirsiniz. Bazı yapılandırma dosyası eksik olabileceğinden getPeople yöntemine bir IOException eklemek istemiyorum. Sadece mantıklı değil.
palto

4

Kontrol edilen istisnalar insanları kaynağa yakın hataları ele almaya teşvik etmelidir. Kaynaktan uzaklaştıkça, çalışmanın ortasında daha fazla işlev sonlandırılır ve sistemin tutarsız bir duruma girme olasılığı artar. Ayrıca, yanlışlıkla yanlış istisnayı yanlışlıkla yakalamanız daha olasıdır.

Ne yazık ki, insanlar ya istisnaları görmezden gelme ya da sürekli artan atış özellikleri ekleme eğiliminde. Bunların her ikisi de, kontrol edilen istisnaların neyi teşvik edeceğini düşünüyor. Prosedür kodunu birçok Getter ve Setter işlevini OO yapan sözde kullanmak için dönüştürmeye benzerler.

Esasen, kontrol edilen istisnalar kodunuzda belirli bir doğruluk derecesini kanıtlamaya çalışıyor. Statik yazmayla hemen hemen aynı fikirdir, çünkü kod çalışmadan önce bazı şeylerin doğru olduğunu kanıtlamaya çalışır. Sorun şu ki, tüm bu ekstra kanıt çaba gerektiriyor ve çabaya değer mi?


2
"İstisnaları yok saymak" genellikle doğrudur - çoğu kez bir istisnaya en iyi yanıt uygulamanın çökmesine izin vermektir. Bu bakış açısının teorik temeli için Bertrand Meyer'ın Nesneye Yönelik Yazılım Yapısı bölümünü okuyun . O göstermektedir istisnalar doğru kullanılması durumunda (1) uygulamanın kilitlenme veya (2) özel duruma neden Sorunu gidermek ve süreci yeniden bakalım: İki doğru yanıtların esasen olduğunu (sözleşme ihlalleri için). Ayrıntılar için Meyer'i okuyun; Bir yorumda özetlemek zor.
Craig Stuntz

1
@Craig Stuntz, istisnaları göz ardı ederek onları yutmak istedim.
Winston Ewert

Ah, bu farklı. Onları yutmamanız gerektiğine katılıyorum.
Craig Stuntz

"İstisnaları görmezden gelmek çoğu zaman doğrudur - çoğu kez bir istisnaya en iyi yanıt uygulamanın çökmesine izin vermektir.": Gerçekten uygulamaya bağlıdır. Bir web uygulamasında yakalanmamış bir istisnanız varsa, olabilecek en kötü şey, müşterinizin bir web sayfasında bir hata mesajı gördüğünü bildirmesi ve birkaç dakika içinde bir hata düzeltmesi uygulayabilmenizdir. Bir uçak inerken bir istisnanız varsa, onu idare edip kurtarmaya çalışmanız daha iyi olur.
Giorgio

@ Giorgio, çok doğru. Her ne kadar merak ediyorum uçak ya da benzeri durumunda kurtarmak için en iyi yolu sistemi yeniden başlatmak.
Winston Ewert
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.