Boş catch blokları neden kötü bir fikirdir? [kapalı]


194

Try-catch hakkında yeni bir soru gördüm , (Jon Skeet dahil) insanların boş catch bloklarının gerçekten kötü bir fikir olduğunu söyledikleri? Neden bu? Boş bir yakalamanın yanlış bir tasarım kararı olmadığı bir durum yok mu?

Örneğin, bazen, bir yerden (webservice, veritabanı) bazı ek bilgiler almak istersiniz ve bu bilgiyi alıp almayacağınızı gerçekten umursamıyorsunuz. Yani anlamaya çalışıyorsunuz ve bir şey olursa sorun değil, sadece bir "catch (istisna yoksayıldı) {}" ekleyeceğim ve hepsi bu


53
Neden boş olması gerektiğini açıklayan bir yorum yazardım.
Mehrdad Afshari

5
... ya da en azından yakalandığını kaydeder.
matt b

2
@ocdecio: temizleme kodu için kaçının, genel olarak kaçının.
John Saunders

1
@ocdecio: try..catch komutunu kullanmaktan kaçınmak için başka bir durum, bilinen hata türleri için özel durumlar yakalamanızdır. örn. sayısal dönüşüm istisnaları
MPritchard

1
@ocdecio - try..finally denemekten daha iyidir ... boş bir hata çünkü yığın yığını devam ettirir - ya çerçeve tarafından ele alınmak veya programı öldürmek ve kullanıcıya göstermek için - her iki sonuç da bir " msgstr "sessiz başarısızlık".
Nate

Yanıtlar:


298

Genellikle boş try-catch kötü bir fikirdir, çünkü bir hata koşulunu sessizce yutuyor ve ardından uygulamaya devam ediyorsunuz. Bazen bu yapılması doğru olan şey olabilir, ancak genellikle bir geliştiricinin bir istisna gördüğünün, bu konuda ne yapacağını bilmediğinin ve bu nedenle sorunu susturmak için boş bir yakalama kullandığının bir işaretidir.

Motor uyarı ışığının üstüne siyah bant yerleştirmenin programlama eşdeğeri.

İstisnalarla nasıl başa çıkacağınızın yazılımın hangi katmanında çalıştığınıza bağlı olduğuna inanıyorum: Yağmur Ormanlarında İstisnalar .


4
O gerçekten nadir durumlarda gerçekten istisna gerekmez ve günlük nedense kullanılamaz, bunun kasıtlı olduğuna emin yorumuna yapmak - ve neden gerekli değildir, ve ben hala eğer log tercih ederim yinelemek o ortamda uygulanabilirdi. Temelde ben bu durumda bir seçenek olsaydı günlüğe kaydedilmesi daha fazla çalışma yapmak. Neyse ki bunun bir sorun olduğu 2 müşterim var ve sadece web sitelerinden kritik olmayan e-postalar gönderirken.
John Rudy

37
Analojiyi de sevin - ve tüm kurallar gibi istisnalar da var. Örneğin, zamanlanmış kayıtlar yapmak istemiyorsanız (VCR'nin ne olduğunu hatırlayan tüm eski halkınız için) VCR'nizdeki yanıp sönen saatin üzerinde siyah bant kullanmanız mükemmeldir.
Michael Burr

3
Kabul edilen uygulamadan herhangi bir ayrılma gibi, uygunsa yapın ve bir sonraki adam ne yaptığınızı ve nedenini bilecek şekilde belgeleyin.
David Thornley

5
@ Jason: en azından, istisnaları neden susturduğunuzu açıklayan ayrıntılı bir yorum eklemelisiniz.
Ned Batchelder

1
Bu cevap iki şey varsaymaktadır: 1. Atılan istisnanın gerçekten anlamlı olduğu ve kodları yazan kişinin ne yaptığını bildiği; 2. İstisnanın gerçekten bir "hata koşulu" olduğunu ve kontrol akışı olarak kötüye kullanılmadığını (ancak bu benim ilk noktamın daha spesifik bir durumudur).
Boris B.12

38

Genel olarak kötü bir fikirdir , çünkü bir başarısızlığın (istisnai durum, daha genel olarak) NO cevabı ile düzgün bir şekilde karşılandığı gerçekten nadir bir durumdur. Bunun da catchötesinde , boş bloklar, istisnai motoru önleyici olarak yapmaları gerektiğini kontrol etmek için istisna motorunu kullanan kişiler tarafından kullanılan yaygın bir araçtır.

Her zaman kötü olduğunu söylemek yanlıştır ... bu çok az şey için doğrudur. Bir hatanın olmasını umursamanız ya da hatanın varlığının bir şekilde bu konuda hiçbir şey yapamayacağınızı gösterdiği durumlar olabilir (örneğin, bir metin günlük dosyasına önceki bir hatayı yazarken ve bir olsun IOExceptionsiz) yeni hata zaten dışarı yazamadım yani.


11

Boş catch blokları kullananların kötü bir programcı olduğunu ve ne yaptığını bilmediğini söyleyecek kadar uzamam ...

Gerekirse boş tutma blokları kullanıyorum. Bazen kullandığım kütüphane programcısı ne yaptığını bilmiyor ve kimsenin ihtiyacı olmadığı durumlarda bile istisnalar atıyor.

Örneğin, bazı http sunucu kitaplığını düşünün, istemcinin bağlantısı kesildiği ve index.htmlgönderilemediği için sunucu istisna atarsa ​​daha az umursamadım .


6
Kesinlikle aşırı genellemelisiniz. Çünkü sen o kimse yok anlamına gelmez gerekmez. Yanıt olarak kesinlikle hiçbir şey yapılamasa bile, terk edilmiş bağlantılarla ilgili istatistik toplama zorunluluğu olan bir yer var. "Kütüphane programcısı ne yaptığını bilmiyor" demek oldukça kaba.
Ben Voigt

8

Gerekçe gösterilebilecek nadir durumlar vardır. Python'da genellikle bu tür bir inşaat görürsünüz:

try:
    result = foo()
except ValueError:
    result = None

Bu nedenle (uygulamanıza bağlı olarak) aşağıdakileri yapmak uygun olabilir:

result = bar()
if result == None:
    try:
        result = foo()
    except ValueError:
        pass # Python pass is equivalent to { } in curly-brace languages
 # Now result == None if bar() returned None *and* foo() failed

Son bir .NET projesinde, belirli bir arabirimi uygulayan sınıfları bulmak için eklenti DLL'leri numaralandırmak için kod yazmak zorunda kaldım. İlgili kod biti (VB.NET'te üzgünüm):

    For Each dllFile As String In dllFiles
        Try
            ' Try to load the DLL as a .NET Assembly
            Dim dll As Assembly = Assembly.LoadFile(dllFile)
            ' Loop through the classes in the DLL
            For Each cls As Type In dll.GetExportedTypes()
                ' Does this class implement the interface?
                If interfaceType.IsAssignableFrom(cls) Then

                    ' ... more code here ...

                End If
            Next
        Catch ex As Exception
            ' Unable to load the Assembly or enumerate types -- just ignore
        End Try
    Next

Bu durumda bile, hatayı bir yere kaydetmenin muhtemelen bir gelişme olacağını kabul ediyorum.


Cevabınızı görmeden önce log4net'ten bu örneklerden biri olarak bahsettim.
Scott Lawrence

7

Boş yakalama blokları genellikle konur çünkü kodlayıcı ne yaptığını gerçekten bilmez. Kuruluşumda, boş bir catch bloğu, istisna ile hiçbir şey yapmamanın neden iyi bir fikir olduğuna dair bir yorum içermelidir.

İlgili bir notta, çoğu kişi {} bloğunun bir catch {} veya son olarak {} ile takip edilebileceğini bilmez, sadece bir tane gereklidir.


1
+1 Daha fazla etki için son cümlede 'veya'
işaretini verirdim

Bu ikinci paragraf dile bağlı olabilir, değil mi?
David Z

3
elbette sürece yakalamak IE6 veya IE7 ;-) ... bahsediyoruz IS gerekli ya nihayet yürütmüyor. (Bu IE8 btw'de düzeltildi)
scunliffe


Çok doğru. Dilleri vurgulamaya değer olabilir.
.Net'in

7

İstisnalar sadece gerçekten bir istisna varsa atılmalıdır - normların ötesinde bir şey oluyor. Boş bir catch bloğu temelde "kötü bir şey oluyor, ama umrumda değil" diyor. Bu kötü bir fikir.

Kural dışı durumu işlemek istemiyorsanız, işleyebilecek bir koda ulaşana kadar yukarı doğru yayılmasına izin verin. İstisna herhangi bir şeyle başa çıkamazsa, uygulamayı kaldırmalıdır.


3
Bazen bunun hiçbir şeyi etkilemeyeceğini bilirsiniz. Öyleyse devam edin ve yapın ve yorum yapın, böylece bir sonraki adam sadece berbat olduğunuzu düşünmez, çünkü beceriksizsiniz.
David Thornley

Evet, her şey için bir zaman ve bir yer var. Genel olarak, boş bir catch bloğunun iyi olduğunu düşünüyorum, kuralın istisnasıdır - bir istisnayı gerçekten göz ardı etmek istediğiniz nadir bir durumdur (genellikle, IMO, istisnaların kötü kullanımının bir sonucudur).
Reed Copsey

2
@David Thornley: Beklenen ve anlamsız bir hatayı mı yoksa yukarı doğru yayılması gereken bir hatayı belirlemek için en azından istisnayı denetlemezseniz, hiçbir şeyi etkilemeyeceğini nasıl anlarsınız?
Dave Sherohman

2
@Dave: catch (Exception) {}Kötü bir fikir olsa da, catch (SpecificExceptionType) {}gayet iyi olabilir. Programcı DID, catch yan tümcesindeki tür bilgilerini kullanarak istisnayı denetler.
Ben Voigt

7

Sadece belirli bir nedenden ötürü bunun yükseltileceğini bildiğiniz belirli bir istisna türünü yakalamanızın iyi olduğunu düşünüyorum ve bu istisnayı bekliyorsunuz ve gerçekten bu konuda bir şey yapmanız gerekmiyor.

Ancak bu durumda bile, bir hata ayıklama mesajı olabilir.


6

Başına Josh Bloch - Item 65: Do İstisnaları görmezden ait Etkili Java :

  1. Boş bir catch bloğu istisnaların amacını yener
  2. En azından catch bloğu, istisnayı görmezden gelmenin neden uygun olduğunu açıklayan bir yorum içermelidir.

3

Boş bir catch bloğu aslında "Hangi hataların atıldığını bilmek istemiyorum, sadece onları görmezden geleceğim" diyor.

VB6'lara benzer On Error Resume Next, ancak istisna atıldıktan sonra try bloğundaki herhangi bir şey atlanacaktır.

Bir şey kırıldığında yardımcı olmaz.


Aslında "On Error Resume Next" daha kötü olduğunu söyleyebilirim - ne olursa olsun bir sonraki satırı deneyeceğim. Boş bir yakalama, deneme ifadesinin kapanış ayracı geçmek için atlayacak
MPritchard

İyi bir nokta. Muhtemelen cevabımda bunu not etmeliyim.
Powerlord

1
Bu tam olarak doğru değil, eğer boş bir denemeniz varsa ... belirli bir istisna türüyle yakalayın, o zaman sadece bu istisna türünü görmezden gelecektir ve bu meşru olabilir ...
Meta-Knight

Ancak, belirli bir istisna türünün atıldığını biliyorsanız, mantığınızı durumla başa çıkmak için try-catch kullanımını önleyecek şekilde yazmak için yeterli bilgiye sahip olabileceğiniz anlaşılıyor.
Scott Lawrence

@Scott: Bazı diller (yani Java) istisnaları kontrol etti ... yakalama blokları yazmak zorunda kaldığınız istisnalar.
Powerlord

3

Bu, "Program akışını kontrol etmek için istisnalar kullanma" ve "Yalnızca istisnai durumlar için istisnalar kullanma" ile el ele gider. Bunlar yapılırsa, istisnalar sadece bir sorun olduğunda meydana gelmelidir. Ve bir sorun varsa, sessizce başarısız olmak istemezsiniz. Sorunu ele almanın gerekli olmadığı nadir anomalilerde, en azından istisnayı günlüğe kaydetmelisiniz, anomali artık bir anomali haline gelmezse. Başarısız olmaktan daha kötü olan tek şey sessizce başarısız olmaktır.


2

Tamamen boş bir catch bloğunun kötü bir fikir olduğunu düşünüyorum, çünkü istisnayı görmezden gelmenin kodun amaçlanan davranışı olduğunu çıkarmanın bir yolu yoktur. Bir istisnayı yutmak ve bazı durumlarda yanlış veya boş veya başka bir değer döndürmek her zaman kötü değildir. .Net çerçevesi, bu şekilde davranan birçok "try" yöntemine sahiptir. Kural dışı bir kural olarak, bir istisnayı yutarsanız, uygulama günlüğü destekliyorsa bir açıklama ve bir günlük ifadesi ekleyin.


1

Bir istisna Çünkü eğer bir sessizce başarısız olası en kötü seçenektir - - Eğer hatalı davranış ve yine oluyor görünümüne hiçbir fikri alırsınız Hiç görmez atılmış. En azından oraya bir günlük mesajı koy! 'Asla olmayacak' bir şey olsa bile!


1

Boş catch blokları, bir programcının bir istisna dışında ne yapacağını bilmediğinin bir göstergesidir. İstisnai olarak kabarmayı ve başka bir deneme bloğu tarafından doğru bir şekilde ele alınmasını önlüyorlar. Her zaman yakaladığınız istisna dışında bir şeyler yapmaya çalışın.


1

Boş catch ifadeleri ile en sinir bozucu bulmak başka bir programcı bunu yaptı. Demek istediğim, herhangi bir boş catch deyimi başka birinden kod hata ayıklamak gerektiğinde böyle bir girişim olması daha zor hale getirir. IMHO catch deyimleri her zaman bir tür hata mesajı göstermelidir - hata ele alınmasa bile en azından algılamalıdır (yalnızca hata ayıklama modunda)


1

Muhtemelen asla doğru olan şey değildir, çünkü olası her istisnayı sessizce geçiyorsunuz . Beklediğiniz özel bir istisna varsa, bunu test etmelisiniz, istisnanız değilse tekrar düşünün.

try
{
    // Do some processing.
}
catch (FileNotFound fnf)
{
    HandleFileNotFound(fnf);
}
catch (Exception e)
{
    if (!IsGenericButExpected(e))
        throw;
}

public bool IsGenericButExpected(Exception exception)
{
    var expected = false;
    if (exception.Message == "some expected message")
    {
        // Handle gracefully ... ie. log or something.
        expected = true;
    }

    return expected;
}

1
Bu, insanlara orada kullanmasını önerdiğiniz standart bir model değil. Çoğu insan, beklemedikleri türden değil, bekledikleri türlerin İstisnalarını yakalardı. Yaklaşımınızın geçerli olacağı bazı koşulları görebiliyorum, sadece insanların böyle şeyler okuma eğiliminde olduğu bir forumda yayınlamaya dikkat edin çünkü ilk etapta anlamıyorlar;)
MPritchard

Amacım, IsKnownException () özel durumun türünü kontrol etmek değildi (evet, bunu farklı catch blokları ile yapmalısınız), bunun yerine beklenen bir istisna olup olmadığını kontrol ediyordu. Daha açık hale getirmek için düzenleyeceğim.
xanadont

Başlangıçta COMExceptions'ı düşünüyordum. Belirli bir ErrorCode'u test edebilir ve beklediğiniz kodları işleyebilirsiniz. Bunu sık sık ArcOjbects ile programlama yaparken yaparım.
xanadont

2
-1 İstisna mesajına dayanarak kodda karar vermek gerçekten kötü bir fikirdir. Tam mesaj nadiren belgelenir ve herhangi bir zamanda değişebilir; bu bir uygulama detayıdır. Veya ileti, yerelleştirilebilir bir kaynak dizesine dayalı olabilir. Her durumda, sadece bir insan tarafından okunmak isteniyordu.
Wim Coenen

Eek. Exception.Message yerelleştirilebilir ve böylece beklediğiniz gibi olmayabilir. Bu sadece yanlış.
frankhommers

1

Genel olarak, yalnızca gerçekten başarabileceğiniz istisnaları yakalamanız gerekir. Bu, istisnaları yakalarken mümkün olduğunca spesifik olmak anlamına gelir. Tüm istisnaları yakalamak nadiren iyi bir fikirdir ve tüm istisnaları göz ardı etmek neredeyse her zaman çok kötü bir fikirdir.

Boş bir catch bloğunun anlamlı bir amacı olduğu birkaç örneği düşünebilirim. Belirli bir istisna ne olursa olsun, sadece eylemi yeniden denemekle yakalarsanız "ele alınır", yakalama bloğunda hiçbir şey yapmanıza gerek kalmaz. Bununla birlikte, istisnanın meydana geldiğini günlüğe kaydetmek iyi bir fikir olacaktır.

Başka bir örnek: CLR 2.0, sonlandırıcı diş üzerindeki işlenmemiş istisnaların işlenme şeklini değiştirdi. 2.0'dan önce bu senaryoda bu sürecin devam etmesine izin verildi. Mevcut CLR'de, sonlandırıcı diş üzerinde işlenmemiş bir istisna olması durumunda işlem sonlandırılır.

Bir sonlandırıcıyı yalnızca gerçekten ihtiyacınız varsa ve sonlandırıcıda mümkün olduğunca az yapmanız gerektiğini unutmayın. Ancak, sonlandırıcınızın yapması gereken her şey bir istisna oluşturabilirse, iki kötülükten daha azını seçmeniz gerekir. İşlenmeyen istisna nedeniyle uygulamayı kapatmak istiyor musunuz? Yoksa az çok tanımsız bir duruma geçmek mi istiyorsunuz? En azından teoride, ikincisi bazı durumlarda iki kötülükten daha az olabilir. Bu durumda, boş yakalama bloğu işlemin sonlandırılmasını engelleyecektir.


1
Örneğin, bazen, bir yerden (webservice, veritabanı) bazı ek bilgiler almak istersiniz ve bu bilgiyi alıp almayacağınızı gerçekten umursamıyorsunuz. Yani anlamaya çalışıyorsunuz ve bir şey olursa sorun değil, sadece bir "catch (istisna yoksayıldı) {}" ekleyeceğim ve hepsi bu

Örneğinize gitmek, bu durumda kötü bir fikir çünkü tüm istisnaları yakalayıp görmezden geliyorsunuz . Sadece yakalayıp EInfoFromIrrelevantSourceNotAvailablegörmezden gelseydin, bu iyi olurdu, ama değilsin. Ayrıca ENetworkIsDownönemli olabilir veya olmayabilir de görmezden geliyorsunuz . Sen görmezden geldiğin ENetworkCardHasMeltedve EFPUHasDecidedThatOnePlusOneIsSeventeenneredeyse kesinlikle önemli olan,.

Boş bir yakalama bloğu, yalnızca önemsiz olduğunu bildiğiniz belirli türdeki istisnaları yakalamak (ve yoksaymak) için ayarlanmışsa sorun değildir. Tüm istisnaları bastırmanın ve sessizce görmezden gelmenin iyi bir fikir olduğu durumlar, ilk önce beklenen / normal / alakasız olup olmadıklarını görmek için onları incelemeyi bırakmadan son derece nadirdir.


1

Bunları kullanabileceğiniz durumlar var, ancak çok seyrek olmalılar. Birini kullanabileceğim durumlar şunları içerir:

  • istisna günlüğü; bağlama bağlı olarak bunun yerine işlenmeyen bir istisna veya mesaj gönderilmesini isteyebilirsiniz.

  • oluşturma veya ses işleme veya bir liste kutusu geri çağırma gibi döngüsel teknik durumlar, davranışın kendisinin sorunu göstereceği, bir istisna atmanın sadece yoluna gireceği ve istisnanın kaydedilmesi muhtemelen 1000'lerin "XXX başarısız oldu" mesajlarıyla sonuçlanacaktır .

  • en azından bir şey kaydediyor olsalar da başarısız olamayacak programlar .

çoğu winforms uygulamaları için, her kullanıcı girişi için tek bir try deyimi olması yeterli bulduk. Aşağıdaki yöntemleri kullanıyorum: (AlertBox sadece hızlı bir MessageBox.Show sarmalayıcıdır)

  public static bool TryAction(Action pAction)
  {
     try { pAction(); return true; }
     catch (Exception exception)
     {
        LogException(exception);
        return false;
     }
  }

  public static bool TryActionQuietly(Action pAction)
  {
     try { pAction(); return true; }
     catch(Exception exception)
     {
        LogExceptionQuietly(exception);
        return false;
     }
  }

  public static void LogException(Exception pException)
  {
     try
     {
        AlertBox(pException, true);
        LogExceptionQuietly(pException);
     }
     catch { }
  }

  public static void LogExceptionQuietly(Exception pException)
  {
     try { Debug.WriteLine("Exception: {0}", pException.Message); } catch { }
  }

Sonra her olay işleyicisi şöyle bir şey yapabilir:

  private void mCloseToolStripMenuItem_Click(object pSender, EventArgs pEventArgs)
  {
     EditorDefines.TryAction(Dispose);
  }

veya

  private void MainForm_Paint(object pSender, PaintEventArgs pEventArgs)
  {
     EditorDefines.TryActionQuietly(() => Render(pEventArgs));
  }

Teorik olarak, istisnaların sonsuz miktarda mesaj üretmemesi için çağrıları yapmak için daha iyi olabilecek TryActionSilently öğesine sahip olabilirsiniz.


1

Yakalama bloğunda ne yapacağınızı bilmiyorsanız, bu istisnayı kaydedebilirsiniz, ancak boş bırakmayın.

        try
        {
            string a = "125";
            int b = int.Parse(a);
        }
        catch (Exception ex)
        {
            Log.LogError(ex);
        }

Bu neden reddedildi?
Vino

0

Asla boş bir yakalama bloğunuz olmamalıdır. Bildiğiniz bir hatayı gizlemek gibidir. En azından zaman için basılırsa daha sonra incelemek için bir günlük dosyasına bir istisna yazmalısınız.

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.