Boş bir catch ifadesi olması hiç iyi oldu mu?


58

Bunu düşündüm ve bir örnek bulamadım. Neden biri bir istisna yakalamak istiyor ve bunun hakkında hiçbir şey yapmıyor? Bir örnek verebilir misin? Belki de asla yapılmaması gereken bir şeydir.


Peki ya sonunda?
Chris

2
btw - Buna SO geçen yıl soruldu: stackoverflow.com/questions/1234343/…
warren

17
en azından neden boş olduğuna dair bir yorum içermelidir .
peterchen

Yanıtlar:


77

Her zaman D'deki dönüştürme hataları gibi şeylerle yapıyorum:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

Bununla birlikte, bir sorun , istisnayı neden görmezden geldiğinizi açıklayan bir yorum olsa bile , tüm catch bloklarının içinde bir şey olması gerektiğini düşünüyorum .

Düzenleme: Ayrıca, böyle bir şey yapacaksanız, sadece göz ardı etmek istediğiniz özel istisnayı yakalamak için dikkatli olmanız gerektiğini vurgulamak isterim. Eski bir düz yapmak catch {}neredeyse her zaman kötü bir şeydir.


15
Açıklama yorumu için +1.
Michael K

Bazı IDE'ler, istisna için özel bir adın (genellikle "yoksay"), aksi takdirde göstereceği uyarıyı bastırarak bilerek yok saydığınızı belirtir; Bu yorum yerini alır.
Alex Feinman

D tanıdık değilim, ama sanırım daha temiz olan TryParse (karakter dizisi, çift valToParse) gibi bir şey yapmanın mümkün olduğunu sanıyorum.
ysolik

4
Vay, aslında D kullanan biri! :-P
James McNellis

4
@Michael söylediği gibi - o değil oldukça orada bir yorum var çünkü boş; Bir açıklama yoksa "kasıtlı olarak bu boş bırakılan" yorumunu eklemek zorunlu olmalı
STW

50

Bir şey yapmadan, istisnayı günlüğe kaydetse bile, istisnayı yutmanın tamam olduğunu düşündüğüm bir örnek, günlük kodunun kendisindedir.

Bir şeyi kaydetmeye çalıştıysanız ve istisna aldıysanız, bu konuda yapabileceğiniz fazla bir şey yoktur:

  • elbette giriş yapamazsınız;
  • rezerv günlüğü mekanizmasına geri dönebilirsiniz, ancak çoğu uygulama o kadar da karmaşık değildir ve yeterince gelişmiş olanlar için aynı tasarım sorunu rezerv günlüğü mekanizmasıyla ortaya çıkar;
  • hızlı başarısız - çoğu uygulama için çok radikal bir çözüm olacaktır;
  • istisnayı atmak, neredeyse kesin olarak kaydetmeye çalışacak yığında bir catch ifadesinde sonuçlanacağından çok az işe yarar ...

Bu, uygulamanın ana işini yapmaya devam etmesine izin vererek, sorunu giderme yeteneğinden ödün vermesine izin vererek, sessizce yutmanın "kötülüğün en az" seçeneğine sahip olmasını sağlar.


10
harika nokta. hata ayıklama kodunun hata ayıklaması her zaman bir zorluktur.
DevSolo

7
Bu, milyon kere. Özellikle giriş yapıyorsanız, korkunç bir durumda olabileceğinizi düşündüğünüzde; hafızanız olabilir, kilitlenebilir, herhangi bir şey olabilir. Bu noktada, bir hata kaydederken ve BU başarısız olursa, yapılacak tek sorumluluk şey değildir; denediğiniz hiçbir şeyin daha da kötüleşmeyeceğinin garantisi yok.
GWLlosa,

Harika nokta. Günlük kodumda, istisna için InnerMessage'ı da eklemeyi seviyorum. Çoğu zaman bu boştur, bu yüzden onu eklemeye çalışmak günlüğün kendisini patlatabilir.
Tangurena

@Tangurena Genellikle boş ise o zaman bununla başa çıkın, üflemeyin. C # 'da genellikle böyle şeyleri korurum. "";
Loren Pechtel

8

Yine de isteğe bağlı olan bir işlem tarafından bir istisna atılırsa, yapılacak hiçbir şey olmayabilir. Giriş yapmak kullanışlı olmayabilir. Bu durumda, sadece onu yakalamak ve hiçbir şey yapmamak isteyebilirsiniz.

Bunu yapıyorsanız, bir yorum ekleyin. Her zaman bir hataya benzeyen herhangi bir şeyi yorumlayın (bir switchifadenin tam ortasında , boş catchblok, bir koşulda atama).

Bunun istisnaların uygun bir kullanımı olmadığını iddia edebilirsiniz, ama bu başka bir soru için.


6

Boş catchbloklar çoğu dilde kod kokusudur. Ana fikir, istisnai durumlar için istisnalar kullanmak ve bunları mantıksal kontrol için kullanmamaktır. Tüm istisnalar bir yerde ele alınmalıdır.

Bu yaklaşımı benimsemenizin bir sonucu olarak, belirli bir uygulama katmanını programladığınızda, birkaç seçeneğiniz vardır:

  • istisna hakkında hiçbir şey yapmayın. Farklı bir katman tarafından yakalanacak ve ele alınacaktır
  • yakala ve düzeltici eylemi gerçekleştir.
  • yakala, bir şeyler yap ama başka bir katmanın ele alması için tekrar fırlat

Bu gerçekten hiçbir şey yapmadan, boş catchbloklar için yer bırakmaz .

EKLENEN EDİLDİ : Diyelim ki istisnaları atmanın program mantığını kontrol etmenin normal yoludur (alternatiflerden biri goto). O zaman catch, bu dilde yazılmış bir programdaki boş bir elseblok, geleneksel bir dilde (veya hiç elseblok yok ) boş bir blok gibidir . Ancak, bunun C #, Java veya C ++ geliştirme toplulukları tarafından önerilen programlama stili olmadığını düşünüyorum.


İstisnaların mantık kontrolü olarak kullanılmasının oldukça yaygın olduğunu düşünüyorum, bu yüzden kendimi sık sık boş veya neredeyse boş tutma bloklarıyla buluyorum.
whatsisname

Boş catch bloğu olduğunu kabul +1 olabilir akış kontrolü için özel durumlar kullanımını belirtir.
John M Gant,

Programlama mantığı için istisnaların kullanılması genellikle kötü bir uygulama olarak kabul edilir. Ancak, şaşırtıcı bir şekilde (istisnalara karşı orijinal argümanım) istisnalar, belirgin bir performans isabetine maruz kalmamaktadır. Bkz codeproject.com/KB/exception/ExceptionPerformance.aspx .
Evan Plaice

6

Bazı durumlarda, Java kesinlikle hiçbir koşulda gerçekleşmeyecek bir istisnayı ele almanızı gerektirir. Bu kodu göz önünde bulundurun:

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}

Java platformunun her bir uygulaması, aşağıdaki standart tabloları desteklemek için gereklidir.

...

UTF-8

Java platformunuzu bozmadan, bu istisnaya neden olmanın hiçbir yolu yoktur. Peki neden onu rahatsız etmiyorsun? Ancak try-catch-yan tümcesini atlatamazsınız.


1
Bu gibi durumlarda, throw new Error(e)hiçbir şeyi kaçırmadığımdan (ya da gerçekten kırılmış bir platformu rapor ettiğimden) kesinlikle emin olmak için cazip davranacağım .
Halle Knast

@HalleKnast Evet. Bu tam olarak burada tartışılmıştır: softwareengineering.stackexchange.com/questions/122233/…
user281377

5

Genel bir kural olarak, hayır. Ya istisnayı yığına atmak ya da ne olduğunu kayıt etmek istersiniz.

Ancak, bunu genellikle dizeleri ayrıştırırken ve sayılara dönüştürürken yaparım (özellikle, bir kez kullanılan ve çeşitliliği uzaklaştıran projeleri eşlerken).

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;

3

Bazı durumlarda istisna istisnai değildir; Aslında, bekleniyor. Bu örneği düşünün:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

Java.lang.Process () öğesinde isAlive () yöntemi olmadığından, hala hayatta olup olmadığını kontrol etmenin tek yolu, işlem hala çalışıyorsa bir IllegalThreadStateException'ı atan exitValue () yöntemini çağırmaktır.


2

Alçak gönüllü deneyimlerime göre, nadiren bu iyi şey. Kilometreler değişebilir.

Neredeyse her zaman bunu kod tabanımızda görüyordum, çünkü yenen istisnanın sakladığı bir hatayı buldum. Başka bir deyişle, herhangi bir kod sağlayarak, uygulamanın bir hata belirtme veya başka bir işlem gerçekleştirme yolu yoktur.

Bazen, örneğin API katmanlarında, istisnaların geçmişte kalmasını istemeyebilir veya izin vermeyebilirsiniz, bu durumda, en genel olanı yakalamaya çalışıp bunları günlüğe kaydederim. Bir kez daha, en azından bir hata ayıklama / teşhis oturumu için bir şans vermek.

Genellikle, boş olması gerekiyorsa, en azından yaptığım şey bir tür iddiada bulunmaktır, bu nedenle en azından bir hata ayıklama oturumu sırasında olur. Bununla başa çıkamazsam, onları tamamen göz ardı etme eğiliminde olduğumu söyledi.


2

IMO, boş catch ifadelerinin tamam olduğu bir yer var. Bir istisna beklediğiniz test durumlarında:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}

+1, bunu yapmaktan nefret ediyorum ama JUnit'te çalışıyor
sal

@ sal: Peki ya @ Test (beklenen = İstisna.class)?
ysolik

@ysolik, kötü alışkanlık
sal

1
@ sal: Neden bu kötü bir alışkanlık?
Adam Lear

ummmm. Bunu ünite test çerçeveleri ile yapmanın yolları vardır. Ör. NUnit. Tahmin edilebilecek bir şeyin başarısız olduğunu test etmenin yararlı olabileceği bazı durumlar vardır. Yine de, üretim kodunda asla yapmam.
Evan Plaice

2

Boş bir yakalama yan tümcesine sahip olmanın haklı olduğu bazı durumlar olduğuna inanıyorum - bunlar, belirli bir işlem başarısız olursa kodun devam etmesini istediğiniz zamanlar olur. Ancak, bu kalıbın kolayca aşırı kullanılabileceğini düşünüyorum, bu yüzden daha iyi bir yolun kullanılmadığından emin olmak için her kullanım yakından incelenmelidir. Özellikle, programı tutarsız bir durumda bırakırsa veya daha sonra başarısız olan kodun başka bir bölümüne götürebilirse, bu kesinlikle yapılmamalıdır.


1

Bir istisna meydana geldiğinde bir uyarı seviyesine sahip olmadığımı sanmıyorum - programlamanın amaçlarından biri kodu geliştirmek değil mi? Bir istisna, zamanın% 10'unda meydana gelirse ve bunu asla bilmiyorsanız, istisna her zaman bu kadar kötü veya daha kötü olacaktır.

Bununla birlikte, diğer tarafı görüyorum, istisna kodun işlenmesinde gerçek bir zararı yoksa, kullanıcıyı neden bu duruma maruz bırakıyor? Genelde uyguladığım çözüm logger sınıfım tarafından kaydedilmektedir (işte şimdiye kadar yazdığım her sınıfta).

Benign bir istisna ise, Logger’ın .Debug () yöntemine çağrı yapıyorum; Aksi takdirde, Logger.Error () (ve (belki) atın).

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

Bu arada, günlüğümü uygulamamda, .Debug () yöntemine çağrı yapmak yalnızca App.Config dosyam program yürütme günlüğü düzeyinin Hata Ayıklama modunda olduğunu belirttiğinde, günlüğe kaydetecektir.


Ya _log.Debug bir istisna atarsa ​​(ne olursa olsun)?
JohnL

O zaman .Debug () istisnayı yiyor ve bundan asla haberim yok. Ancak, günlüğe kaydedicim hakkında, genellikle istisnalar atan kod hakkında düşündüğümden çok daha fazla güven duyuyorum. Bununla ilgili endişelerim varsa, alıcı bloğuna girmeyi izleyen ve daha sonra için saklayan bir çeşit kalıp uygulayabileceğimi farz ediyorum. Her durumda - alınan nokta
Tim Claason

1

Varlık kontrolü iyi bir kullanım durumudur:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

Başka bir durum, finallyyan tümce kullanıldığında:

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

ECMAScript'te bu ve benzeri kullanım durumlarıyla ilgili olan mandal bağlamanın ihmal edilmesine izin verme önerisi vardır .

Referanslar


Başka bir örnek: Düğümlerde, fs.exists yönteminin (doğru veya yanlış döndüren) kullanım dışı bırakılması ( nodejs.org/dist/latest-v10.x/docs/api/… ) içinde bir istisna atan fs.access lehine Bir dosya yoksa dava. Eğer biri sadece dosya varsa bir şey yapmak isterse, catch cümlesi tamamen gereksizdir.
systemovich

0

Bunun gibi bir şeyi yapmam için tek ihtiyacım olan şey, bir konsol uygulaması için bir günlük sınıfındaydı. Hatayı STDOUT'a yayan, dosyayı bir dosyaya kaydeden, ardından uygulamayı> 0 hata koduyla kapatan bir üst düzey global catch işleyicisi vardı.

Buradaki sorun, bazen, dosyaya giriş yapmanın başarısız olmasıydı. Dizin izinleri dosyayı yazmanıza engel oldu, dosya tamamen kilitlendi, her neyse. Böyle bir durumda, istisnayı başka bir yerde bulunduğum gibi idare edemedim (özel bilgileri ayrıntılarıyla yakalayın, ilgili ayrıntıları girin , daha iyi bir istisna türünü sarın, vb.) ) zaten başarısız olan bir dosyaya yazmaya çalışıyorum. Yine başarısız olduklarında ... Nereye gittiğimi görüyorsun. Sonsuz bir döngüye girer.

Try {} bloklarından bazılarını bırakırsanız, bir mesaj kutusunda görünen istisna olabilir (sessiz bir yapılandırma uygulaması için istediğinizi değil). Bu yüzden günlük dosyasına yazan bu yöntemde, boş bir catch işleyicim var. Bu, hala> 0 hata kodunu aldığınız için hatayı gömmez, yalnızca sonsuz döngüyü durdurur ve uygulamanın zarif bir şekilde çıkmasına izin verir.

Elbette, neden boş olduğunu açıklayan bir yorum var.

(Bunu daha önce gönderecektim, sadece unutulmaktan alevlenmekten korkuyordum. Çünkü sadece ben değilim ...)


0

Sonunda en kritik parçaya ne olursa olsun, bir dizinin yürütülmesi gerektiğinde durum iyidir.

Örneğin. Ana kontrol cihazına hareket kontrolü iletişimde. Acil durumlarda hareketi durdurmak, yörünge üretimini durdurmak, motorları yavaşlatmak, molaları etkinleştirmek, yükselticiyi devre dışı bırakmak ve bundan sonra veri yolu gücünü kesmek için bir takım hazırlık adımları vardır. Her şey sırayla yapılmalı ve adımlardan biri başarısız olursa, donanımın zarar görmesi tehlikesiyle bile olsa, geri kalan adımların gerçekleştirilmesi gerekir. Yukarıdakilerin hepsi başarısız olsa bile, kill bus gücünün yine de gerçekleşmesi gerektiğini söyleyin.


Bu hiçbir şey yapmadığın anlamına gelmez, sadece yaptığın şeyin akışı durdurmadığı anlamına gelir. İstisnalarınızı yakalayın, hafızaya kaydedin (diske yazma gecikmesi yok), ardından nihayet bir ifadeyle gücü kesin. Sonra kaydedilen bilgilerle ne yapacaksanız yapın.
Loren Pechtel

0

Hatadan kurtulmak için sistem kaynaklarını incelikle kapatma

Örneğin. Eğer kullanıcıya geri bildirimde sağlamaz arka planda bir hizmeti çalıştırıyorsanız, kullanıcıya hata bir göstergesini itmek istemeyebilir ama do zarif bir şekilde kullanılmakta olan kaynaklara göz kapatmak gerekir.

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

İdeal olarak, hataları yakalamak ve bunları test etmek için konsola veya bir günlük dosyasına yazdırmak için catch hata ayıklama modunda kullanırsınız. Bir üretim ortamında, arka plan hizmetlerinin genellikle bir hata atıldığında kullanıcıyı rahatsız etmemesi beklenir, bu nedenle hata çıktısının bastırılması gerekir.

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.