문제

FXCop으로 일부 레거시 코드를 분석하는 동안 try 블록 내에서 일반 예외 오류를 포착하는 것이 정말 좋지 않거나 특정 예외를 찾아야 한다는 생각이 들었습니다.엽서에 대한 생각을 부탁드립니다.

도움이 되었습니까?

해결책

분명히 이것은 유일한 실제 대답이 "상황에 따라 다르다"는 질문 중 하나입니다.

그것이 의존하는 가장 중요한 것은 예외를 포착하는 위치입니다.일반적으로 라이브러리는 프로그램의 최상위 수준(예:기본 메소드나 컨트롤러의 액션 메소드 상단에서) 잡는 것에 더 자유로울 수 있습니다.

그 이유는 다음과 같습니다.사용자에게 알릴 수 있도록 버블링을 선호하는 "OutOfMemoryException"과 같이 라이브러리와 관련이 없는 문제를 가릴 수 있기 때문에 라이브러리에서 모든 예외를 포착하고 싶지는 않습니다.반면, 예외를 포착하고 표시한 다음 종료하는 main() 메서드 내에서 예외 포착에 대해 이야기하는 경우...글쎄, 여기서는 거의 모든 예외를 잡아내는 것이 안전할 것입니다.

모든 예외를 잡는 데 있어서 가장 중요한 규칙은 모든 예외를 조용히 삼켜서는 안 된다는 것입니다.예를 들어Java에서는 다음과 같습니다.

try { 
    something(); 
} catch (Exception ex) {}

또는 Python에서는 다음과 같습니다.

try:
    something()
except:
    pass

이는 추적하기 가장 어려운 문제일 수 있기 때문입니다.

좋은 경험 법칙은 스스로 적절하게 처리할 수 있는 예외만 포착해야 한다는 것입니다.예외를 완전히 처리할 수 없다면 처리할 수 있는 사람에게 알려주어야 합니다.

다른 팁

애플리케이션의 프런트 엔드에서 일부 로깅 및 정리 코드를 수행하지 않는 한 모든 예외를 포착하는 것은 좋지 않다고 생각합니다.

내 기본 경험 법칙은 예상하는 모든 예외를 포착하는 것이며 그 밖의 모든 것은 버그입니다.

모든 것을 파악하고 계속 진행하면 자동차 대시보드의 경고등 위에 반창고를 붙이는 것과 비슷합니다.더 이상 볼 수 없지만 모든 것이 괜찮다는 의미는 아닙니다.

예!(지원서의 "상단" 제외)

예외를 포착하고 코드 실행을 계속하도록 허용함으로써 특정 문제를 처리하고 회피하거나 수정하는 방법을 알고 있음을 나타냅니다.당신은 이것이라고 말하고 있습니다. 회복 가능한 상황.예외 또는 SystemException을 포착한다는 것은 IO 오류, 네트워크 오류, 메모리 부족 오류, 코드 누락 오류, 널 포인터 역참조 등과 같은 문제를 포착한다는 것을 의미합니다.이런 일을 처리할 수 있다고 말하는 것은 거짓말입니다.

잘 구성된 애플리케이션에서는 이러한 복구 불가능한 문제를 스택 상위에서 처리해야 합니다.

또한 코드가 발전함에 따라 함수가 추가된 새로운 예외를 포착하는 것을 원하지 않을 것입니다. 미래에 호출된 메소드에.

제 생각에는 모든 예외를 잡아야 한다고 생각합니다. 예상하다, 그러나 이 규칙은 인터페이스 로직을 제외한 모든 항목에 적용됩니다.호출 스택 전체에서 모든 예외를 포착하고 일부 로깅을 수행하고 사용자에게 피드백을 제공하며 필요하고 가능하다면 정상적으로 종료하는 방법을 만들어야 합니다.

사용자에게 친숙하지 않은 일부 스택 추적이 화면에 덤프되어 애플리케이션이 충돌하는 것보다 더 나쁜 것은 없습니다.이는 코드에 대한 (아마도 원치 않는) 통찰력을 제공할 뿐만 아니라 최종 사용자를 혼란스럽게 하고 때로는 경쟁 애플리케이션에 겁을 주기도 합니다.

이 문제에 관해 많은 철학적 토론(논쟁에 가깝습니다)이 있었습니다.개인적으로 나는 당신이 할 수 있는 최악의 일은 예외를 삼키는 것이라고 생각합니다.그 다음 최악의 상황은 사용자가 기술적인 엉터리로 가득 찬 불쾌한 화면을 보게 되는 표면까지 예외가 발생하도록 허용하는 것입니다.

제가 생각하는 요점은 두 가지입니다.

첫째, 어떤 예외가 발생했는지 모르는 경우 어떻게 복구할 수 있습니까?사용자가 파일 이름을 잘못 입력할 것으로 예상되면 FileNotFoundException이 발생하고 사용자에게 다시 시도하라고 지시할 수 있습니다.동일한 코드에서 NullReferenceException이 발생하고 사용자에게 다시 시도하라고 지시했다면 사용자는 무슨 일이 일어났는지 알 수 없습니다.

둘째, FxCop 지침은 라이브러리/프레임워크 코드에 중점을 두고 있습니다. 모든 규칙이 EXE 또는 ASP.Net 웹 사이트에 적용되도록 설계된 것은 아닙니다.따라서 모든 예외를 기록하고 애플리케이션을 훌륭하게 종료하는 전역 예외 처리기를 갖는 것이 좋습니다.

모든 예외를 포착할 때의 문제는 예상하지 못한 예외나 실제로 해야 할 예외를 포착할 수 있다는 것입니다. ~ 아니다 잡기.사실 모든 종류의 예외는 문제가 발생했음을 나타내며 계속하기 전에 이를 정렬해야 합니다. 그렇지 않으면 추적하기 쉽지 않은 데이터 무결성 문제 및 기타 버그가 발생할 수 있습니다.

한 가지 예를 들자면, 한 프로젝트에서 CriticalException이라는 예외 유형을 구현했습니다.이는 개발자 및/또는 관리 직원의 개입이 필요한 오류 상태를 나타냅니다. 그렇지 않으면 고객에게 잘못 요금이 청구되거나 기타 데이터 무결성 문제가 발생할 수 있습니다.단순히 예외를 기록하는 것만으로는 충분하지 않아 이메일 경고를 보내야 하는 다른 유사한 경우에도 사용할 수 있습니다.

예외의 개념을 제대로 이해하지 못한 또 다른 개발자는 이 예외를 잠재적으로 발생시킬 수 있는 일부 코드를 모든 예외를 삭제하는 일반 try...catch 블록에 래핑했습니다.다행히 발견했지만 심각한 문제를 초래할 수도 있었습니다. 특히, 잡아야 했던 "매우 드문" 코너 케이스가 예상보다 훨씬 더 흔한 것으로 밝혀졌기 때문입니다.

따라서 일반적으로 일반적인 예외를 잡는 것은 당신이 알고 있는 것이 100% 확실하지 않는 한 좋지 않습니다. 정확히 어떤 종류의 예외가 발생하고 어떤 상황에서 발생하는지.의심스러우면 대신 최상위 예외 처리기로 버블링하도록 하세요.

여기서도 비슷한 규칙은 System.Exception 유형의 예외를 발생시키지 않는다는 것입니다.귀하(또는 다른 개발자)는 호출 스택의 상위에서 특정 예외를 포착하고 다른 개발자는 이를 처리하도록 할 수 있습니다.

(단, 주의할 점이 하나 있습니다..NET 2.0에서는 스레드에 포착되지 않은 예외가 발생하면 전체 앱 도메인이 언로드됩니다.따라서 일반 try...catch 블록에서 스레드의 주요 본문을 래핑하고 거기에서 발견된 모든 예외를 전역 예외 처리 코드에 전달해야 합니다.)

글쎄요, 여러 개의 catch 블록이 있는 경우 예외가 무엇인지에 따라 다르게 반응할 수 있다는 점을 제외하면 일반적인 예외를 잡는 것과 특정 예외를 잡는 것 사이에는 아무런 차이가 없습니다.

결론적으로 둘 다 잡을 것이다. IOException 그리고 NullPointerException 일반으로 Exception, 그러나 프로그램이 반응하는 방식은 다를 수 있습니다.

나는 예외를 잡아서 기록하고 다시 던지는 악마의 옹호자 역할을 하고 싶습니다.예를 들어, 코드 어딘가에 예상치 못한 예외가 발생하는 경우 이를 포착하고 간단한 스택 추적에서는 사용할 수 없는 의미 있는 상태 정보를 기록한 다음 이를 상위 계층으로 다시 던져서 다루다.

완전히 다른 두 가지 사용 사례가 있습니다.첫 번째는 대부분의 사람들이 생각하는 것으로, 확인된 예외가 필요한 일부 작업에 try/catch를 배치하는 것입니다.이것은 결코 만능이 되어서는 안 됩니다.

그러나 두 번째는 프로그램이 계속될 수 있을 때 프로그램이 중단되는 것을 방지하는 것입니다.이러한 경우는 다음과 같습니다.

  • 모든 스레드의 최상위 (기본적으로 예외는 추적 없이 사라집니다!)
  • 절대 종료되지 않을 것으로 예상되는 기본 처리 루프 내부
  • 하나의 실패가 다른 실패를 중지해서는 안 되는 객체 목록을 처리하는 루프 내부
  • "메인" 스레드의 최상위 - 메모리가 부족할 때 stdout에 약간의 데이터를 덤프하는 등 여기에서 충돌을 제어할 수 있습니다.
  • 코드를 실행하는 "러너"가 있는 경우(예를 들어 누군가가 리스너를 추가하고 귀하가 리스너를 호출하는 경우) 코드를 실행할 때 Exception을 포착하여 문제를 기록하고 다른 리스너에게 계속 알릴 수 있도록 해야 합니다.

이러한 경우 프로그래밍/예기치 못한 오류를 포착하고 기록하고 계속하기 위해 항상 Exception(때로는 Throwable일 수도 있음)을 포착하기를 원합니다.

좋은 지침은 프레임워크 내에서 특정 예외만 포착하는 것이라고 생각합니다(호스트 애플리케이션이 디스크 가득 차는 등의 극단적인 경우를 처리할 수 있도록). 하지만 왜 우리가 모든 것을 포착할 수 없어야 하는지 모르겠습니다. 우리 애플리케이션 코드의 예외.간단히 말해서, 무슨 일이 일어나더라도 앱이 충돌하는 것을 원하지 않는 경우가 있습니다.

대부분의 경우 일반적인 예외를 포착할 필요가 없습니다.물론 선택의 여지가 없는 상황도 있지만, 이 경우에는 왜 잡아야 하는지 확인해 보는 것이 더 낫다고 생각합니다.어쩌면 디자인에 뭔가 문제가 있을 수도 있습니다.

일반적인 예외를 포착하면 불타는 건물 안에 다이너마이트 막대를 들고 신관을 끄는 것과 같은 느낌이 듭니다.잠시 동안은 도움이 되지만 어쨌든 다이너마이트는 잠시 후에 터질 것입니다.

물론 일반적인 예외를 포착해야 하는 상황이 있을 수 있지만 디버그 목적으로만 그렇습니다.오류와 버그는 숨겨야 할 것이 아니라 수정되어야 합니다.

인앱 결제(온라인 TrivialDrive 예제)와 함께 사용한 IabManager 클래스의 경우 때때로 많은 예외를 처리한다는 것을 알았습니다.예측할 수 없는 지경에 이르렀습니다.

대부분의 예외가 발생하는(구매가 아닌 소비) 예외가 발생한 후 인앱 제품을 소비하려는 시도를 중단하는 한 안전할 것이라는 것을 깨달았습니다.

방금 모든 예외를 일반 예외로 변경했으며, 이제 예측할 수 없는 무작위 예외가 발생하는 것에 대해 걱정할 필요가 없습니다.

전에:

    catch (final RemoteException exc)
    {
        exc.printStackTrace();
    }
    catch (final IntentSender.SendIntentException exc)
    {
        exc.printStackTrace();
    }
    catch (final IabHelper.IabAsyncInProgressException exc)
    {
        exc.printStackTrace();
    }
    catch (final NullPointerException exc)
    {
        exc.printStackTrace();
    }
    catch (final IllegalStateException exc)
    {
        exc.printStackTrace();
    }

후에:

    catch (final Exception exc)
    {
        exc.printStackTrace();
    }

인기 없는 의견:설마.

의미 있게 복구할 수 있는 모든 오류를 포착하세요.때로는 그게 전부일 때도 있습니다.

내 경험상 그게 더 중요함 어디 예외가 실제로 발생한 것보다 예외가 발생했습니다.예외를 엄격하게 유지한다면 일반적으로 유용할 어떤 것도 삼키지 않을 것입니다.오류 유형으로 인코딩된 정보의 대부분은 보조 정보이므로 일반적으로 효과적으로 오류를 포착하게 됩니다. 모두 어쨌든 그 중 하나입니다(그러나 이제 가능한 예외의 전체 집합을 얻으려면 API 문서를 찾아야 합니다).

Python의 경우와 같이 거의 모든 경우에 맨 위로 올라와야 하는 일부 예외가 있음을 명심하세요 KeyboardInterrupt 그리고 SystemExit.다행스럽게도 Python의 경우 이러한 항목은 예외 계층의 별도 분기에 보관되므로 다음을 잡아서 버블링되도록 할 수 있습니다. Exception.잘 설계된 예외 계층 구조는 이러한 유형의 작업을 매우 간단하게 만듭니다.

일반적인 예외를 포착하면 심각한 문제가 발생하는 주요 시간은 정리해야 하는 리소스를 처리할 때입니다(아마도 finally 절), 포괄적인 핸들러는 그러한 종류의 사항을 쉽게 놓칠 수 있기 때문입니다.다행스럽게도 이는 다음을 사용하는 언어에서는 실제로 문제가 되지 않습니다. defer, Python과 같은 구성 with, 또는 C++ 및 Rust에서는 RAII입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top