빈 캐치 블록이 왜 나쁜 생각입니까? [닫은]


194

try-catch에 대한 질문을 보았습니다 .Jon Skeet을 포함한 어떤 사람들은 빈 캐치 블록이 정말 나쁜 생각이라고 말합니까? 왜 이런가요? 빈 캐치가 잘못된 설계 결정이 아닌 상황이 없습니까?

예를 들어, 때때로 당신은 어딘가에서 추가 정보를 원하고 (웹 서비스, 데이터베이스)이 정보를 얻을지 여부는 실제로 신경 쓰지 않습니다. 그래서 당신은 그것을 얻으려고 노력하고, 어떤 일이 발생해도 괜찮습니다. "catch (Exception ignore) {}"를 추가하면됩니다.


53
왜 비어 있어야 하는지를 설명하는 의견을 작성하고 싶습니다.
Mehrdad Afshari

5
... 적어도 그것을 잡았다는 것을 기록하십시오.
matt b

2
@ocdecio : 정리 코드를 피하십시오. 일반적으로 피하십시오.
John Saunders

1
@ocdecio : try..catch를 사용하지 않는 또 다른 경우는 알려진 유형의 실패에 대한 예외를 포착하는 경우입니다. 예 : 숫자 변환 예외
MPritchard

1
@ocdecio-try..finally는 try..empty catch보다 낫습니다. 오류는 스택을 계속 유지하기 때문입니다. 프레임 워크에서 처리하거나 프로그램을 종료하고 사용자에게 표시하려면 두 결과가 모두 " 자동 실패 "
Nate

답변:


298

일반적으로 빈 try-catch는 오류 조건을 자동으로 삼킨 후 실행을 계속하기 때문에 나쁜 생각입니다. 때때로 이것은 옳은 일일 수 있지만, 종종 개발자가 예외를 보았고 이에 대해 무엇을해야하는지 알지 못했기 때문에 빈 캐치를 사용하여 문제를 침묵시킵니다.

엔진 경고등에 검은 테이프를 붙이는 것과 동등한 프로그래밍입니다.

예외를 처리하는 방법은 사용중인 소프트웨어의 계층에 따라 다릅니다 . Rainforest의 예외 .


4
나는 그 정말 드문 상황에서 정말 예외를 필요하지 않습니다 로깅이 어떤 이유로 사용할 수없는, 나는 그것이 의도적입니다 있는지 의견을 확인 - 왜 그것이 필요하지, 난 여전히 경우를 기록하는 것을 선호 거라고 투자 의견 그것은 그 환경에서 가능했습니다. 기본적으로 나는 로깅이 그 상황에서 옵션이었을 때보 다 더 많은 의견을 제시합니다. 운 좋게도이 문제가 발생하는 클라이언트는 2 명 뿐이며 웹 사이트에서 중요하지 않은 전자 메일을 보낼 때만 가능합니다.
John Rudy

37
또한 비유를 좋아하며 모든 규칙과 마찬가지로 예외가 있습니다. 예를 들어, 시간 기록을하지 않으려는 경우 (VCR이 무엇인지 기억하는 노인들에게) VCR의 깜박이는 시계 위에 검은 색 테이프를 사용하는 것이 좋습니다.
Michael Burr

3
받아 들여진 연습에서 벗어난 것처럼, 적절한 경우이를 수행하고 다음 사람이 당신이 한 일과 이유를 알 수 있도록 문서화하십시오.
David Thornley

5
@Jason : 최소한 예외를 침묵시키는 이유를 설명하는 자세한 설명을 포함해야합니다.
Ned Batchelder

1
이 답변은 다음 두 가지를 가정합니다. 1. 예외가 발생한다는 것은 실제로 의미있는 예외이며, 코드를 작성한 사람은 자신이하는 일을 알고있었습니다. 2. 예외는 실제로 "오류 상태"이며 제어 흐름으로 남용되지 않습니다 (이것이 나의 첫 번째 포인트의보다 구체적인 경우 임에도 불구하고).
보리스 B.

38

일반적으로 나쁜 생각 입니다 . 실패 (예외 조건,보다 일반적으로)가 아무런 반응없이 적절하게 충족되는 진정한 희귀 조건이기 때문입니다. 또한 빈 catch블록은 예외 엔진을 사용하여 선점 적으로 수행해야하는 오류를 확인하는 사람들이 사용하는 일반적인 도구입니다.

항상 나쁘다는 말 은 사실이 아닙니다. 오류가있는 것을 신경 쓰지 않거나 오류의 존재로 인해 어쨌든 아무것도 할 수 없음을 나타내는 상황이있을 수 있습니다 (예 : 텍스트 로그 파일에 이전 오류를 기록 할 때 당신은 IOException어쨌든 새로운 오류를 쓸 수 없다는 것을 의미합니다).


11

빈 캐치 블록을 사용하는 사람이 나쁜 프로그래머이며 자신이 무엇을하는지 모른다고 말하는 것까지는 말하지 않습니다.

필요한 경우 빈 캐치 블록을 사용합니다. 때로는 내가 사용하는 라이브러리의 프로그래머가 자신이 무엇을하는지 알지 못하고 아무도 필요없는 상황에서도 예외가 발생합니다.

예를 들어, 일부 http 서버 라이브러리를 고려하십시오. 클라이언트의 연결이 끊어져서 index.html보낼 수 없기 때문에 서버에서 예외가 발생하면 신경 쓰지 않아도됩니다.


6
당신은 확실히 지나치게 일반화되고 있습니다. 그냥 있기 때문에 당신 이 그 아무도하지 않는다 의미하지 않는다 필요가 없습니다. 응답으로 전혀 아무것도 할 수 없더라도 어딘가에 버려진 연결에 대한 통계를 수집해야하는 사람이 있습니다. "라이브러리 프로그래머가 자신이하는 일을 모른다"고 가정하는 것은 무례합니다.
Ben Voigt

8

정당화 될 수있는 경우는 드물다. 파이썬에서는 종종 이런 종류의 구성을 볼 수 있습니다.

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

따라서 (응용 프로그램에 따라) 다음을 수행해도됩니다.

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

최근 .NET 프로젝트에서 특정 인터페이스를 구현하는 클래스를 찾기 위해 플러그인 DLL을 열거하는 코드를 작성해야했습니다. VB.NET의 관련 코드 비트는 다음과 같습니다.

    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

이 경우에도, 어딘가에서 실패를 기록하는 것이 아마도 개선 일 것임을 인정합니다.


귀하의 답변을보기 전에 log4net을 해당 인스턴스 중 하나로 언급했습니다.
스콧 로렌스

7

빈 캐치 블록은 일반적으로 코더가 실제로 무엇을하는지 알지 못하기 때문에 삽입됩니다. 우리 조직에서는 빈 캐치 블록에 예외없이 아무 것도하지 않는 것이 좋은 생각 인 이유를 설명해야합니다.

관련 메모에서 대부분의 사람들은 try {} 블록 뒤에 catch {} 또는 finally {}가 올 수 있다는 것을 알지 못하며 하나만 필요합니다.


1
+1 나는 마지막 문장에서 '또는'스트레스를 추가했다
MPritchard

두 번째 단락은 언어에 따라 다를 수 있습니다.
David Z

3
물론하지 않는 한 당신은 캐치 IE6이나 IE7 ;-) ...에 대해 얘기하고 IS 필요하거나 마지막으로 실행되지 않습니다. (이것은 IE8 btw에서 수정되었습니다)
scunliffe


매우 사실입니다. 언어를 강조 할 가치가 있습니다. 나는 그물 괜찮 생각
MPritchard

7

예외는 실제로 예외가있는 경우에만 발생해야합니다. 표준을 넘어서는 일이 발생합니다. 빈 캐치 블록은 기본적으로 "나쁜 일이 일어나고 있지만 신경 쓰지 않습니다"라고 말합니다. 이것은 나쁜 생각입니다.

예외를 처리하지 않으려면 예외를 처리 할 수있는 코드에 도달 할 때까지 위쪽으로 전파하십시오. 예외를 처리 할 수있는 것이 없으면 응용 프로그램을 중단해야합니다.


3
때로는 그것이 영향을 미치지 않을 것이라는 것을 알고 있습니다. 그런 다음 계속 진행하고 주석을 달아서 다음 사람이 당신이 무능하기 때문에 당신이 망쳤다 고 생각하지 않도록하십시오.
David Thornley

예, 모든 것을위한 시간과 장소가 있습니다. 그러나 일반적으로 비어있는 catch 블록이 규칙에 대한 예외라고 생각합니다. 예외를 실제로 무시하려는 경우는 거의 없습니다 (일반적으로 IMO는 예외를 잘못 사용했기 때문에 발생합니다).
Reed Copsey

2
@David Thornley : 예외를 검사하여 예상하고 의미없는 오류인지 아니면 위쪽으로 전파해야하는지 여부를 결정하지 않으면 어떤 영향도 미치지 않을지 어떻게 알 수 있습니까?
Dave Sherohman

2
@ 데이브 : catch (Exception) {}나쁜 생각이지만 catch (SpecificExceptionType) {}완벽하게 괜찮을 수도 있습니다. 프로그래머 DID는 catch 절의 유형 정보를 사용하여 예외를 검사합니다.
Ben Voigt

7

특정 이유로 인해 발생 하는 특정 예외 유형을 발견하면 예외가 발생할 것으로 예상되며 실제로 예외를 기대할 필요는 없습니다.

그러나이 경우에도 디버그 메시지가 순서가있을 수 있습니다.


6

조쉬 블로흐 - 항목 65 : 음주 예외 무시하지효과적인 자바 :

  1. 빈 캐치 블록은 예외의 목적을 무효화
  2. 최소한 catch 블록에는 예외를 무시하는 것이 적절한 이유를 설명하는 주석이 포함되어야합니다.

3

빈 캐치 블록은 본질적으로 "어떤 오류가 발생했는지 알고 싶지 않습니다. 그냥 무시하겠습니다."

On Error Resume Next예외가 발생한 후 try 블록의 모든 항목을 건너 뛴다는 점을 제외하면 VB6과 유사합니다 .

어떤 것이 깨질 때 도움이되지 않습니다.


실제로 "On Error Resume Next"가 더 나쁘다고 말합니다. 빈 캐치가 try 문을 닫는 중괄호를 뛰어 넘을 것입니다.
MPritchard

좋은 지적. 아마 내 대답에 주목해야 할 것입니다.
Powerlord

1
만약 당신이 특정한 예외 유형을 가진 빈 try ... catch를 가지고 있다면 이것은 사실이 아닙니다.이 유형의 예외만을 무시할 것이며, 그것은 합법적 일 수도 있습니다 ...
Meta-Knight

그러나 특정 유형의 예외가 발생한다는 것을 알고 있다면 상황을 처리하기 위해 try-catch를 사용하지 않는 방식으로 논리를 작성하기에 충분한 정보가있는 것 같습니다.
스콧 로렌스

@Scott : 특정 언어 (예 : Java)에서 예외를 확인했습니다. 예외를 잡아서 catch 블록을 작성해야합니다.
Powerlord

3

"프로그램 흐름을 제어하기 위해 예외를 사용하지 마십시오."및 "예외 상황에서는 예외 만 사용하십시오."와 함께 사용됩니다. 이 작업이 완료되면 문제가있을 때만 예외가 발생해야합니다. 그리고 문제가 있다면 조용히 실패하고 싶지 않습니다. 문제를 처리 할 필요가없는 드문 예외에서는 예외가 더 이상 예외가되지 않을 경우를 대비하여 최소한 예외를 기록해야합니다. 실패보다 더 나쁜 것은 조용히 실패하는 것입니다.


2

예외를 무시하는 것이 코드의 의도 된 동작이라고 추론 할 수있는 방법이 없기 때문에 완전히 비어있는 catch 블록은 나쁜 생각이라고 생각합니다. 예외를 삼키고 false 또는 null 또는 다른 경우에 다른 값을 반환하는 것이 반드시 나쁘지는 않습니다. .net 프레임 워크에는 이러한 방식으로 작동하는 많은 "시도"메소드가 있습니다. 예외를 삼킨 경우 경험에 따라 응용 프로그램에서 로깅을 지원하는 경우 주석과 로그 문을 추가하십시오.


1

예외 발생하면 조용히 실패하는 것이 최악의 옵션입니다 . 예외 발생하지 않습니다. 최소한 거기에 로그 메시지를 넣으십시오! 그것이 결코 일어날 수없는 일이더라도!


1

빈 캐치 블록은 예외로 수행 할 작업을 모르는 프로그래머를 나타냅니다. 그들은 다른 try 블록에 의해 예외가 버블 링되고 올바르게 처리되지 않도록 예외를 억제하고 있습니다. 잡는 것을 제외하고는 항상 무언가를 시도하십시오.


1

빈 catch 문으로 가장 성가신 것은 다른 프로그래머가 할 때입니다. 내 말은 빈 캐치 명령문을 다른 사람으로부터 코드를 디버깅해야 할 때 그러한 작업을 수행하는 것이 더 어려워진다는 것입니다. IMHO catch 문은 항상 일종의 오류 메시지를 표시해야합니다. 오류를 처리하지 않더라도 최소한 오류를 감지해야합니다 (디버그 모드에서만 변경).


1

가능한 모든 예외를 조용히 전달하기 때문에 아마도 결코 올바른 일이 아닙니다 . 예상되는 특정 예외가있는 경우 예외를 테스트하고 예외가 아닌 경우 다시 던져야합니다.

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
실제로 사람들에게 사용하도록 조언하는 표준 패턴은 아닙니다. 대부분의 사람들은 예상하지 못한 유형이 아닌 예상되는 모든 유형의 예외를 포착합니다. 나는 당신의 접근 방식이 유효한 상황을 볼 수 있습니다. 사람들이 처음에는 이해하지 못하기 때문에 이런 것들을 읽는 경향이있는 포럼에 게시하는 것을 조심하십시오.)
MPritchard

내 의도는 IsKnownException ()이 예외 유형을 확인하는 것이 아니라 (예, 다른 catch 블록으로 수행해야 함) 예상되는 예외인지 확인하는 것입니다. 좀 더 명확하게 편집하겠습니다.
xanadont

나는 원래 COMExceptions에 대해 생각하고있었습니다. 특정 ErrorCode를 테스트하고 예상 코드를 처리 할 수 ​​있습니다. ArcOjbects로 프로그래밍 할 때이 작업을 자주 수행합니다.
xanadont

2
-1 예외 메시지를 기반으로 코드에서 결정을 내리는 것은 정말 나쁜 생각입니다. 정확한 메시지는 거의 문서화되어 있지 않으며 언제든지 변경 될 수 있습니다. 구현 세부 사항입니다. 또는 메시지는 현지화 가능한 리소스 문자열을 기반으로 할 수 있습니다. 어쨌든 그것은 단지 인간에 의해 읽히기위한 것입니다.
Wim Coenen

Eek. 예외. 메시지가 현지화되어 예상 한 것과 다릅니다. 이것은 단지 잘못이다.
Frankhommers

1

일반적으로 실제로 처리 할 수있는 예외 만 잡아야합니다. 이는 예외를 잡을 때 가능한 구체적이어야 함을 의미합니다. 모든 예외를 잡는 것이 좋은 생각은 아니며 거의 모든 예외를 무시하는 것은 거의 항상 나쁜 생각입니다.

빈 캐치 블록에 의미있는 목적이있는 몇 가지 사례 만 생각할 수 있습니다. 특정 예외가 무엇이든 잡기 만 재 시도하여 "잡기"하는 경우 catch 블록에서 아무것도 할 필요가 없습니다. 그러나 여전히 예외가 발생했다는 사실을 기록하는 것이 좋습니다.

또 다른 예 : CLR 2.0은 종료 자 스레드에서 처리되지 않은 예외를 처리하는 방식을 변경했습니다. 2.0 이전에는 프로세스가이 시나리오에서 살아남을 수있었습니다. 현재 CLR에서 종료 자 스레드에서 처리되지 않은 예외가 발생하면 프로세스가 종료됩니다.

파이널 라이저가 실제로 필요한 경우에만 파이널 라이저를 구현해야하며 파이널 라이저에서 가능한 한 약간만 수행해야합니다. 그러나 파이널 라이저가해야 할 일이 예외를 던질 수 있다면, 두 가지 악 중 작은 것을 골라야합니다. 처리되지 않은 예외로 인해 응용 프로그램을 종료 하시겠습니까? 아니면 다소 정의되지 않은 상태로 진행 ​​하시겠습니까? 적어도 이론적으로 후자는 어떤 경우에는 두 가지 악 중에서 더 적을 수 있습니다. 이 경우 빈 캐치 블록으로 인해 프로세스가 종료되지 않습니다.


1
예를 들어, 때때로 당신은 어딘가에서 추가 정보를 원하고 (웹 서비스, 데이터베이스)이 정보를 얻을지 여부는 실제로 신경 쓰지 않습니다. 그래서 당신은 그것을 얻으려고 노력하고, 어떤 일이 발생해도 괜찮습니다. "catch (Exception ignore) {}"를 추가하면됩니다.

따라서 예를 들어 모든 예외를 포착하고 무시하기 때문에이 경우 나쁜 생각입니다 . 당신이 잡기 만 EInfoFromIrrelevantSourceNotAvailable무시하고 있다면 괜찮을 것입니다. 또한 ENetworkIsDown중요하거나 중요하지 않은을 무시하고 있습니다. 당신은 무시 ENetworkCardHasMelted하고 EFPUHasDecidedThatOnePlusOneIsSeventeen있습니다. 거의 확실합니다.

빈 캐치 블록은 중요하지 않은 것으로 알려진 특정 유형의 예외 만 캐치 (및 무시)하도록 설정된 경우 문제가되지 않습니다. 예상 / 정상 / 부적절한 지 여부를 확인하기 위해 먼저 예외를 검사하지 않고 모든 예외 를 억제하고 자동으로 무시하는 것이 좋은 경우는 매우 드 rare니다.


1

당신이 그들을 사용할 수있는 상황이 있지만, 매우 드물게 있어야합니다. 내가 사용할 수있는 상황은 다음과 같습니다.

  • 예외 로깅; 상황에 따라 처리되지 않은 예외 또는 메시지가 대신 게시 될 수 있습니다.

  • 렌더링 또는 사운드 처리 또는 목록 상자 콜백과 같은 반복되는 기술 상황에서 동작 자체가 문제를 보여주고 예외를 throw하면 예외가 발생하며 예외를 로깅하면 1000의 "XXX 실패"메시지가 나타납니다. .

  • 최소한 무언가를 로깅해야하지만 실패 할 수없는 프로그램 .

대부분의 winforms 응용 프로그램의 경우 모든 사용자 입력에 대해 단일 try 문이 있으면 충분하다는 것을 알았습니다. 나는 다음과 같은 방법을 사용합니다 : (AlertBox는 빠른 MessageBox.Show 래퍼입니다)

  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 { }
  }

그런 다음 모든 이벤트 핸들러는 다음과 같은 작업을 수행 할 수 있습니다.

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

또는

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

이론적으로 TryActionSilently를 사용할 수 있습니다. 이는 예외가 끝없는 양의 메시지를 생성하지 않도록 호출 렌더링에 더 좋습니다.


1

catch 블록에서 수행 할 작업을 모르는 경우이 예외를 기록 할 수 있지만 비워 두지 마십시오.

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

이것이 왜 하향 조정 되었습니까?
Vino

0

빈 캐치 블록이 없어야합니다. 그것은 당신이 알고있는 실수를 숨기는 것과 같습니다. 최소한 시간을 눌렀다면 나중에 검토 할 수 있도록 예외를 로그 파일에 작성해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.