문제

방금 봤어요 Try-Catch에 대한 질문, 어떤 사람들 (Jon Skeet 포함)은 빈 캐치 블록이 정말 나쁜 생각이라고 말합니까? 왜 이건? 빈 캐치가 잘못된 디자인 결정이 아닌 상황이 없습니까?

예를 들어, 때로는 어딘가 (웹 서비스, 데이터베이스)에서 추가 정보를 얻기를 원 하며이 정보를 얻을 수 있는지 여부는 신경 쓰지 않습니다. 그래서 당신은 그것을 얻으려고 노력하고, 어떤 일이 발생하면 괜찮습니다. 나는 단지 "catch (예외 무시) {}를 추가 할 것입니다. 그리고 그게 전부입니다.

도움이 되었습니까?

해결책

일반적으로 빈 시도 캐치는 조용히 오류 조건을 삼키고 실행을 계속하기 때문에 나쁜 생각입니다. 때때로 이것은 옳은 일일 수도 있지만 종종 개발자가 예외를보고, 그것에 대해 무엇을 해야할지 몰랐기 때문에 빈 잡기를 사용하여 문제를 침묵시키는 신호입니다.

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

예외를 다루는 방법은 작업중인 소프트웨어의 계층에 달려 있다고 생각합니다. 열대 우림의 예외.

다른 팁

그들은 나쁜 생각입니다 일반적으로 실패 (예외적 인 조건,보다 일반적으로)가 응답이없는 상태에서 적절하게 충족되는 것은 정말 드문 조건이기 때문입니다. 그 외에도 비어 있습니다 catch 블록은 예외 엔진을 사용하여 오류를 선택하는 사람들이 선제 적으로 수행 해야하는지 확인하는 일반적인 도구입니다.

그것이 말하는 것입니다 언제나 나쁜 것은 사실이 아닙니다 ... 그것은 거의 사실입니다. 오류가 있거나 오류의 존재가 어쨌든 아무것도 할 수 없음을 나타내는 상황이있을 수 있습니다 (예 : 텍스트 로그 파일에 이전 오류를 작성할 때 및 당신은 얻습니다 IOException, 어쨌든 새로운 오류를 쓸 수 없다는 것을 의미합니다).

나는 빈 캐치 블록을 사용하는 사람이 나쁜 프로그래머이며 그가 무엇을하고 있는지 모른다고 말하는 한 나는 물건을 늘리지 않을 것입니다 ...

필요한 경우 빈 캐치 블록을 사용합니다. 때때로 내가 소비하는 도서관의 프로그래머는 그가 무엇을하고 있는지 알지 못하고 아무도 필요하지 않을 때도 상황에서도 예외를 던집니다.

예를 들어, 일부 HTTP 서버 라이브러리를 고려하면 클라이언트가 연결이 끊어지고 클라이언트가 제외하고 예외가 발생하면 신경 쓰지 않을 수 있습니다. index.html 보낼 수 없었습니다.

정당화 될 수있는 드문 사례가 있습니다. 파이썬에서는 종종 이런 종류의 구성을 볼 수 있습니다.

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

이 경우에도 실패를 어딘가에 로깅하는 것이 아마도 개선 될 것임을 인정합니다.

코더가 실제로 무엇을하고 있는지 알지 못하기 때문에 빈 캐치 블록이 일반적으로 들어갑니다. 내 조직에서 빈 캐치 블록에는 예외를 제외하고 아무것도하지 않는 이유에 대한 의견이 포함되어야합니다.

관련 메모에서, 대부분의 사람들은 Catch {} 또는 마지막으로 {}를 사용하여 시도 {} 블록을 따라갈 수 있다는 것을 알지 못합니다. 하나만 필요합니다.

예외는 진정으로 예외가있는 경우에만 발생해야합니다. 빈 캐치 블록은 기본적으로 "나쁜 일이 일어나고 있지만 나는 단지 상관하지 않습니다"라고 말합니다. 이것은 나쁜 생각입니다.

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

당신이 잡으면 괜찮다고 생각합니다 특정한 당신이 알고있는 예외 유형은 하나만 올릴 것입니다. 특정한 이유, 그리고 당신은 그 예외를 기대하고 실제로 그것에 대해 아무것도 할 필요가 없습니다.

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

조쉬 블로 치 - 항목 65 : 예외를 무시하지 마십시오효과적인 자바:

  1. 빈 캐치 블록은 예외의 목적을 물리칩니다
  2. 최소한 캐치 블록에는 예외를 무시하는 것이 왜 적절한 지 설명하는 의견이 포함되어야합니다.

빈 캐치 블록은 본질적으로 "어떤 오류가 발생하는지 알고 싶지 않고, 나는 단지 그들을 무시할 것입니다."

VB6과 비슷합니다 On Error Resume Next, 예외가 발생한 후 시도 블록에있는 모든 것이 건너 뜁니다.

무언가가 깨질 때 도움이되지 않습니다.

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

나는 완전히 빈 캐치 블록이 예외를 무시하는 것이 코드의 의도 된 동작이라고 추론 할 방법이 없기 때문에 나쁜 생각이라고 생각합니다. 예외를 삼키고 어떤 경우에는 거짓 또는 널 또는 다른 값을 반환하는 것이 반드시 나쁘지는 않습니다. .NET 프레임 워크에는 이런 식으로 작동하는 많은 "시도"메소드가 있습니다. 경험상 예외를 삼키면 응용 프로그램이 로깅을 지원하는 경우 주석과 로그 문을 추가하십시오.

예외이라면 ~이다 당신은 그것을 볼 수 없을 것입니다 - 조용히 실패하는 것은 최악의 옵션입니다 - 당신은 잘못된 행동을 얻을 것이며 그것이 어디에서 일어나고 있는지 알지 못할 것입니다. 적어도 거기에 로그 메시지를 넣으십시오! '결코 일어나지 않을 수있는 일이더라도'라는 것이더라도!

빈 캐치 블록은 프로그래머가 예외로 무엇을 해야할지 모른다는 표시입니다. 그들은 또 다른 시도 블록으로 버블 링하고 올바르게 처리 될 수있는 예외를 억제하고 있습니다. 항상 당신이 잡는 것을 제외하고 무언가를 시도하십시오.

비어있는 캐치 진술로 가장 성가신 것은 다른 프로그래머가 할 때입니다. 내가 의미하는 바는 다른 사람의 코드를 디버그해야 할 때 빈 캐치 문장이 그러한 사업을 더 어렵게 만들어야한다는 것입니다. IMHO 캐치 문은 항상 어떤 종류의 오류 메시지를 표시해야합니다. 오류가 처리되지 않더라도 적어도이를 감지해야합니다 (디버그 모드에서만 al.)

조용히 지나가기 때문에 아마도 옳은 일이 아닙니다. 모든 가능한 예외. 특정 예외가있는 경우 예외가 아닌 경우 Rethrow를 테스트해야합니다.

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

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

빈 캐치 블록에 의미있는 목적이있는 몇 가지 인스턴스 만 생각할 수 있습니다. 특정한 예외가 있으면, 당신이 잡는 것이 행동을 다시 시작하여 "처리"되는 경우 캐치 블록에서 아무것도 할 필요가 없습니다. 그러나 예외가 발생했다는 사실을 기록하는 것이 여전히 좋은 생각입니다.

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

결승 분기가 실제로 필요한 경우에만 최종 결정을 구현해야하며 최종화기에서 최대한 조금 수행해야합니다. 그러나 최종화자가해야 할 일이 무엇이든 예외를 던질 수 있다면, 두 가지 악의 덜 악을 선택해야합니다. 처리되지 않은 예외로 인해 신청서를 종료 하시겠습니까? 아니면 다소 정의되지 않은 상태에서 진행하고 싶습니까? 적어도 이론적으로 후자는 어떤 경우에는 두 가지 악 중 덜적일 수 있습니다. 이 경우 빈 캐치 블록은 프로세스가 종료되는 것을 방지합니다.

예를 들어, 때로는 어딘가 (웹 서비스, 데이터베이스)에서 추가 정보를 얻기를 원 하며이 정보를 얻을 수 있는지 여부는 신경 쓰지 않습니다. 그래서 당신은 그것을 얻으려고 노력하고, 어떤 일이 발생하면 괜찮습니다. 나는 단지 "catch (예외 무시) {}를 추가 할 것입니다. 그리고 그게 전부입니다.

그래서, 당신의 모범을 가지고 가면, 당신이 잡고 무시하기 때문에 그 경우에는 나쁜 생각입니다. 모두 예외. 당신이 붙잡고 있다면 EInfoFromIrrelevantSourceNotAvailable 그리고 그것을 무시하고, 그것은 괜찮을 것이지만, 당신은 그렇지 않습니다. 당신은 또한 무시하고 있습니다 ENetworkIsDown, 중요하거나 중요하지 않을 수도 있습니다. 당신은 무시하고 있습니다 ENetworkCardHasMelted 그리고 EFPUHasDecidedThatOnePlusOneIsSeventeen, 거의 확실히 중요합니다.

빈 캐치 블록은 중요하지 않은 것으로 알고있는 특정 유형의 예외 만 예외로 설정되도록 설정된 경우 문제가되지 않습니다. 진압하고 조용히 무시하는 것이 좋은 생각 모두 예외는 먼저 예상/정상/관련이 있는지 여부를 확인하기 위해 먼저 검사를 중단하지 않고 매우 드 rare니다.

당신이 그것들을 사용할 수있는 상황이 있지만, 매우 드물게되어야합니다. 내가 사용할 수있는 상황에는 다음이 포함됩니다.

  • 예외 로깅; 컨텍스트에 따라 대신 처리되지 않은 예외 또는 메시지를 대신 게시 할 수 있습니다.

  • 렌더링 또는 사운드 처리와 같은 기술 상황을 루프하는 것 또는 Listbox Callback, 동작 자체가 문제를 보여주고 예외를 던지면 예외가 발생하며 예외를 기록하면 "XXX에 실패"메시지가 1000으로 발생할 수 있습니다. .

  • 그 프로그램 할 수 없습니다 비록 그들이 여전히 무언가를 기록하고 있어야하지만 실패합니다.

대부분의 WinForms 응용 프로그램의 경우 모든 사용자 입력에 대해 단일 시도 명령문이 충분하다는 것을 알았습니다. 다음 방법을 사용합니다.

  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));
  }

이론적으로, 당신은 tryactionsilly를 가질 수 있습니다. 이는 예외가 끝없는 양의 메시지를 생성하지 않도록 전화를 렌더링하는 데 더 좋을 수 있습니다.

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

캐치 블록에서 무엇을 해야할지 모른다면이 예외를 기록 할 수 있지만 비워 두지 마십시오.

        try
        {
            string a = "125";
            int b = int.Parse(a);
        }
        catch (Exception ex)
        {
            Log.LogError(ex);
        }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top