Java uygulamasında çalışma zamanı istisnası atma


12

Teknik bir müşteri rolünde müvekkilim için kurumsal Java uygulaması tasarlayan bir yüklenici olarak çalışıyorum. Uygulama son kullanıcılar tarafından kullanılacak ve biz ayrılırken uygulamayı destekleyecek bir destek ekibi olacak.

Birlikte çalıştığım diğer teknik müşteriler, istisna işlemenin kodu kirleteceği izlenimi altındadır. Sistem, kontrol edilen istisnaları yalnızca Hizmet katmanından atmalı ve kodun geri kalanı, denetlenmeyen istisnaları işlemeye gerek kalmaması için diğer tüm katmanlardan çalışma zamanı istisnaları atmalıdır.

Bir iş uygulamasında kontrol edilmeyen bir istisna atmaya ne gerek var?

Çalışma zamanı istisnaları hakkındaki geçmiş deneyimimden:

1) İşaretlenmeyen istisnalar, Javadoc'ta bile görünmediği için kodu öngörülemez hale getirir.

2) Bir iş uygulamasında denetlenmeyen istisnalar atmak mantıklı değildir, çünkü onu attığınızda ve doğrudan Kullanıcıların yüzüne giderken, kullanıcıya nasıl açıklarsınız? 500 -Internal Error. Contact AdministratorSon kullanıcı veya uygulamayı yöneten destek ekibi için hiçbir şey ifade etmeyen web uygulamasını yeterince gördüm .

3) Çalışma zamanı istisnalarını atmak, istisnayı atan sınıf kullanıcılarını hata ayıklamak ve istisnanın neden atıldığını görmek için kaynak kodundan geçmeye zorlar. Bu, yalnızca çalışma zamanı istisnasının Javadoc'unun mükemmel bir şekilde belgelenmesi durumunda kaçınılmazdır, ki bu asla bir durum değildir.


Hizmet Katmanı'nın ne olduğunu açıklayabilir misiniz? Katman kullanıcıdan en uzak mı yoksa kullanıcıya en yakın mı?
Manoj R

Bu soru neden SO'ya uymuyor?
Bjarke Freund-Hansen

@Manoj R: Hiçbiri. Hizmet katmanı veya katmanı, DB teknolojisinin ayrıntılarından ve istemci sunumundan ayrı olarak iş kurallarının ve mantığının uygulandığı yerdir.
Michael Borgwardt

6
Kontrol edilmeyen istisnalar [...] Javadoc'ta bile görünmez. => Bu @throwsetiketle belgelerseniz , bu arada iyi bir uygulama olarak görünürler .
Ocak'ta Assylias

4
@SureshKoya Etkili Java, Madde 62: Her yöntemle atılan tüm özel durumları belgeleyin. Ayıkla: Bir yöntemin atabileceği denetlenmeyen her özel durumu belgelemek için Javadoc @throwsetiketini kullanın , ancak yöntem bildirimine denetlenmeyen özel durumlar dahil etmek için throws anahtar sözcüğünü kullanmayın.
Ocak'ta Assylias

Yanıtlar:


13

İşaretli istisnalar dil tasarımında başarısız bir expiment'tir. Sizi son derece sızdıran soyutlamalar ve kirli kodlara sahip olmaya zorlarlar. Mümkün olduğunca kaçınılmalıdır.

Puanlarınız için:

1) İşaretli istisnalar kodu kirli hale getirir ve her yerde göründüklerinden daha az tahmin edilemez .

2) İşaretli bir istisna kullanıcıya nasıl daha iyi gösteriliyor? İşaretli ve denetlenmeyen istisnalar arasındaki tek gerçek fark tekniktir ve yalnızca kaynak kodunu etkiler.

3) Yığın izlerini hiç duydunuz mu? İşaretlenmiş veya işaretlenmemiş olsun, istisnanın tam olarak nereye atıldığını size söylerler. Aslında, kontrol edilen istisnalar hata ayıklama için daha kötü olma eğilimindedir, çünkü genellikle daha uzun ve daha çirkin yığın izlerine yol açarlar veya sarma yanlış yapıldığı için birlikte kaybedilirler.

İki tür istisna vardır: "normalde" meydana gelen ve genellikle meydana geldikleri yere çok yakın olan ve gerçekten istisnai olan ve çok yüksek bir katmanda genel olarak ele alınabilenler (sadece geçerli eylemi iptal edip / hata göster).

İşaretli istisnalar, bu ayrımı istisnaların tanımlandığı noktada dil sözdizimine koyma girişimidir. Bununla ilgili problemler

  • Fark gerçekten arayan kişiye bağlıdır , istisnayı atan kod değil
  • Bir istisnanın anlamsal anlamıyla tamamen dikeydir, ancak onu sınıf hiyerarşisine bağlamak sizi ikisini karıştırmaya zorlar
  • Bütün istisnalar, bir hatayı sessizce kaybetme veya kodu orta seviyelerde kirletmek zorunda kalmadan, onları hangi düzeyde yakalayacağınıza karar verebilmenizdir; kontrol edilen istisnalar ikinci avantajı kaybeder.

1. Kontrol edilmemiş bir istisna olması durumunda, bir çağrının kontrol edilmemesine neden olup olmayacağını bile bilemezsiniz. 2. "Bir istisnanın anlamsal anlamıyla tamamen dikeydir, ancak onu sınıf hiyerarşisine bağlamak sizi ikisini karıştırmaya zorlar" dediğinde, sanırım sınıf hiyerarşisi yerine çağrı hiyerarşisi demek istediniz.
randominstanceOfLivingThing

2
@Suresh Koya: Hayır, sınıf hiyerarşisi demek istedim, bir bildirimin , DB erişimiyle ilgili bir hata nedeniyle bir hata SQLException extends Exceptionatmayı seçmenin SQLExceptionistisnanın kontrol edildiği anlamına geldiği anlamına geliyor. Javadoc yorumlarında kontrol edilmemiş istisnaları gayet iyi belgeleyebilirsiniz. Diğer tüm diller için iyi çalışır.
Michael Borgwardt

1
@MichaelBorgwardt "İşaretli istisnalar dil tasarımında başarısız bir exprimenttir", eğer değilse daha fazla okumak istiyorum kişisel görüşünüzdür. Herhangi bir otantik bağlantı çok yardımcı olacaktır.
Vipin

2
@Vipin: Bu benim kişisel görüşüm, ancak diğer birçok kişinin paylaştığı bir fikir, örneğin Bruce Eckel: mindview.net/Etc/Discussions/CheckedExceptions - ve Java'nın tanıtılmasından bu yana 20 yıl içinde başka bir dilin kontrol edilmiş istisnaları kabul etmemesi kendisi için ...
Michael Borgwardt

2

Benim görüşüm, atılan istisna türünün kodunuzun ne yaptığına bağlı olmasıdır.

Oldukça sık olabileceğini düşündüğümde kontrol edilen istisnalar atıyorum (örneğin tehlikeli verileri giren kullanıcılar) ve arama kodunun durumu ele almasını bekliyorum.

Arama kodunun işlemesini beklemediğim nadir bir durum olduğunda, denetlenmeyen / çalışma zamanı özel durumları (sık sık kontrol edilmez) atarım. Bir örnek, asla olmasını beklemediğim garip bellekle ilgili bir çeşit hata olabilir. İşaretlenmemişse, uygulamayı kaldırmayı beklediğiniz türden hatalar vardır.

Herhangi bir destek seviyesi olmayan bir kullanıcının önünde istisna olmamalıdır. Sadece "lütfen bu hata dökümünü bir e-postaya kesin ve yapıştırın" olsa bile. Hiçbir şey kullanıcı için bir hata olduğunu söylemekten daha sinir bozucu değildir, ancak düzeltilmesini başlatmak için yapabilecekleri hiçbir ayrıntı veya işlem yapılmaz.

Tahminimce, bahsettiğiniz felsefe iki kaynaktan birinden geliyor:

  • Tembel programcılar iş yapmaktan kaçınmaya çalışıyor.
  • Ya da diğer yöne giden kodu desteklemek zorunda olan geliştiriciler. yani aşırı hata işleme. Akış kontrolü ve diğer yanlış amaçlar için büyük miktarda istisna işleme içeren, çoğu hiçbir şey yapmayan veya daha da kötüsü olan kod türü kullanılır.

Bir şey oldukça sık olabilirse, bu bir istisna değildir. Ancak, kullanıcının hiçbir fikri olmayan hatanın atılmaması gerektiğine karar verdiler.
Manoj R

Felsefeni kabul ediyorum. Kullanıcılar için geliştirdiğiniz bir uygulamada, bir Çalışma Zamanı istisnası atmak için ne gerekir?
randominstanceOfLivingThing

Ayrıca, bir Çalışma Zamanı istisnası atılmış olsa bile, @assylias'ın işaret ettiği konvansiyonu tercih ederim.
randominstanceOfLivingThing

1

Denetlenmeyen çalışma zamanı özel durumları istemiyorsanız, neden java kullanıyorsunuz? NullPointerException, ArithmeticException, ArrayIndexOutOfBounds istisnaları, vb. Hemen hemen her yerde çalışma zamanı istisnaları olasılığı vardır.

Bir keresinde, örneğin bir SAP NetWeaver yüklemesi gibi bazı J2EE sistemlerinin günlük dosyalarını okuduğunuzda, bu tür istisnaların her zaman tam anlamıyla gerçekleştiğini göreceksiniz.


Java dil spesifikasyonundan: "Çalışma zamanı istisna sınıfları (RuntimeException ve alt sınıfları) derleme zamanı kontrolünden muaftır, çünkü Java programlama dili tasarımcılarının kararında, bu tür istisnaları beyan etmek, doğruluğun belirlenmesinde önemli ölçüde yardımcı olmaz Java programlama dilinin birçok işlemi ve yapısı çalışma zamanı istisnalarına neden olabilir. "
randominstanceOfLivingThing

1
Konuştuğunuz çalışma zamanı istisnası, Java çalışma zamanı sisteminin neden belirli bir çağrıyı yapmaya çalıştığınıza dair bir ipucu olmadığı için Java'dan kaynaklananlardır. Örneğin: null olan bir yöntemi çağırıyorsanız NullPointerException oluşacaktır. Bu durumda, Java çalışma zamanı sisteminin programcılar için doğru bir sözcüğü yoktur ve arayanı bir NullPointerException ile tokatlar. Üzücü kısmı arayan Netweaver ürünü size sattı ve bir kullanıcı olarak şimdi kötü programlama kurbanı. Testçiler, tüm sınır testlerini yapmadığı için eşit olarak suçlanacaklardır.
randominstanceOfLivingThing

1

İstisna yönetimi için aklınızda bulundurmanız gereken birkaç kural vardır. Ancak önce, istisnaların kod tarafından maruz kalan arayüzün bir parçası olduğunu hatırlamanız gerekir ; belgelemek . Arayüz genel bir arayüz olduğunda bu özellikle önemlidir, ancak özel arayüzlerde de çok iyi bir fikirdir.

İstisnalar, yalnızca kodun kendileriyle mantıklı bir şey yapabileceği noktada ele alınmalıdır. En kötü kullanım seçeneği, sadece tam olarak doğru seçenek olduğunda yapılması gereken onlar hakkında hiçbir şey yapmamaktır. (Kodumda böyle bir durum olduğunda, bu etki için bir yorum ekledim, bu yüzden boş gövde hakkında endişelenmemeyi biliyorum.)

İkinci en kötü seçenek, orijinal neden olarak eklenmeden ilgisiz bir istisna atmaktır. Buradaki sorun, orijinal istisna dahilinde sorunun teşhisine izin verecek bilgilerin kaybolmasıdır; hiç kimsenin bir şey yapamayacağı bir şey yaratıyorsunuz (“işe yaramadığından şikayet etmek dışında, hepimiz bu hata raporlarından nasıl nefret ettiğimizi biliyoruz ).

Çok daha iyi istisna günlüğü. Bu, birisinin sorunun ne olduğunu öğrenmesine ve düzeltmesine izin verir, ancak istisnayı yalnızca harici bir bağlantı üzerinden başka türlü kaybolacağı veya rapor edileceği noktada günlüğe kaydetmelisiniz. Bunun nedeni, daha sık oturum açmanın bu kadar önemli bir sorun olması değil, daha çok günlük tutmanın, daha fazla bilgi içermeden günlüğün daha fazla yer kaplaması anlamına gelmesidir. İstisna kaydolduktan sonra, kısa versiyonun eşleşebilmesi için bu raporda iyi bir vicdanla kullanıcı / müşteriye bir bildirim bildirebilirsiniz (üretim zamanını veya başka bir korelasyon tanımlayıcısını da eklediğiniz sürece) gerekirse detay ile).

En iyi seçenek, elbette, istisnayı tamamen ele almak ve hata durumunun tamamını ele almaktır. Bunu yapabilirseniz, elbette yapın! Hatta istisnayı günlüğe kaydetmekten kaçınabileceğiniz anlamına da gelebilir.

Bir istisnayı ele almanın bir yolu, sorunun daha üst düzey bir tanımını sağlayan başka bir istisna atmaktır (örneğin, “ failed to initialize” yerine “ index out of bounds”). İstisnanın nedeni hakkındaki bilgileri kaybetmediğiniz sürece bu iyi bir modeldir; causeüst düzey istisnayı başlatmak veya ayrıntıyı günlüğe kaydetmek için ayrıntılı istisnayı kullanın (yukarıda tartışıldığı gibi). IPC çağrısı gibi süreçler arası bir sınırı geçmek üzereyken günlüğe kaydetme en uygun yöntemdir, çünkü bağlantının diğer ucunda düşük düzey özel durum sınıfının bulunacağının garantisi yoktur. Dahili bir sınırı geçerken ekli neden olarak tutmak en uygunudur.

Gördüğünüz başka bir desen, yakala ve bırak:

try {
    // ...
} catch (FooException e) {
    throw e;
}

Bu, istisnaların kendi başına geçmesine izin veremeyeceğiniz anlamına gelen diğer maddelerden tür kısıtlamalarınız yoksa , bir anti-desendir catch. Sonra sadece Java'nın çirkin bir özelliği.

Eğer olması dışında kontrol istisnalar ve kontrolsüz olanlar arasındaki gerçek fark yok yok zorundadır işaretli istisnalar o cross yöntemi sınırları beyan ederim. @throwsKodunuz tarafından kasıtlı olarak atıldıklarını biliyorsanız , kontrol edilmeyen istisnaları ( javadoc yorumuyla) belgelemek hala iyi bir fikirdir . Kasıtlı olarak java.lang.Errorveya alt sınıflarını atmayın (bir JVM uygulaması yazmıyorsanız).

Görüş: Beklenmeyen bir hata durumu her zaman kodunuzdaki bir hatayı temsil eder. İşaretli istisnalar bu tehdidi yönetmenin bir yoludur ve geliştiricilerin kasıtlı olarak hata durumlarını ele alma sorununu önlemenin bir yolu olarak kontrol edilmeyen istisnaları kullandıkları yerlerde, bir süre temizlemek zorunda kalacak çok fazla teknik borç oluşturuyorsunuz. sağlam bir kod istiyorsanız. Özensiz hata işleme profesyonelce (ve hata işlemeye bakmak, bir programcının gerçekten ne kadar iyi olduğunu belirlemenin iyi bir yoludur).


0

Bence uygulama kurtarabilir SADECE kontrol istisna atmak gerektiğini düşünüyorum. Bu nedenle, kitaplığınızın kullanıcıları bu istisnaları yakalamalı ve kurtarmak için gerekenleri yapmalıdır. Başka her şey işaretlenmemelidir.

Örnek olarak,

Uygulamanız bir dosyadan veya veritabanından veri yüklerse. Sonra,..

try {
  File data = new File(...);
  // parse file here
} catch (Exception ex) {
  throw new MissingDataFileException("data file not found");
}

arayan her zaman işaretli MissingDataFileException'ı yakalayabilir ve ardından verileri veritabanından yüklemeyi deneyebilir.

try {
  Connection con = DriverManager.getConnection( host, username, password );
  // query data here
} catch (Exception ex) {
  throw new RuntimeException("better call Saul!");
}

1
Saul 3 yıl önce bir araba kazasında öldü. Başarısız! ;-)
Donal Fellows
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.