문제

나는 주변의 코드가 특정 예외를 잡을 것이라는 것을 알고 예외를 던지거나 다시 던지는 인스턴스를 처리했습니다.하지만 예외가 잡히지 않을 것이라는 것을 알고 예외를 던지고 싶은 경우가 있습니까?

아니면 적어도 예외를 포착하지 못하시나요?

예외가 올바르게 처리되지 않으면 응용 프로그램이 즉시 중단됩니까?그래서 나는 의도적으로 응용 프로그램이 죽도록 놔두기를 원하는지 묻고 있는 것 같습니다.

도움이 되었습니까?

해결책

응용 프로그램이 주로 다른 클라이언트가 사용하고 독립형이 아닌 경우 일반적으로 처리 방법을 모르거나 원하지 않는 상태가 발생하는 경우 일반적으로 예외를 제외하는 것이 좋습니다. 당신이 그것을 회복하는 방법. 고객은 자신이 던질 수있는 예외를 처리하는 방법을 결정할 수 있어야합니다.

반면에, 신청인 경우 ~이다 예외를 던지는 엔드 포인트는 본질적으로 사람들에게 무언가 잘못되었음을 알리는 알림 메커니즘이됩니다. 이 경우 몇 가지 사항을 고려해야합니다.

  • 응용 프로그램의 지속적인 실행은 얼마나 중요합니까? 이 오류는 실제로 복귀 할 수 없습니까? 예외를 던지고 프로그램을 종료하는 것은 우주 왕복선에서하고 싶은 일이 아닙니다.

  • 실제 로깅의 프록시로 예외를 사용하고 있습니까? 이것을 할 이유는 거의 없습니다. 대신 실제 로깅 메커니즘을 고려하십시오. 예외를 잡고 로거가 무슨 일이 있었는지 알아 내도록하십시오.

  • 예외를 직접 던져서 무엇을 전달하려고합니까? 새로운 예외를 던질 때의 가치가 무엇인지 스스로에게 물어보고, 원하는 것을 할 수있는 더 좋은 방법이 없는지주의 깊게 고려하십시오.

  • 예외를 포착하지 않으면 자원이 나쁜 상태로 남을 수 있습니다. 당신이 우아하게 나가지 않으면, 일반적으로 상황은 당신을 위해 정리되지 않습니다. 이 작업을 수행 해야하는 경우하고있는 일을 이해해야합니다. 그리고 그것을 잡지 않겠다면, 적어도 try-finally 차단하여 약간의 정리를 할 수 있습니다.

다른 팁

내가 얼마 전에 본 아주 좋은 규칙이 있습니다.

방법이 그 이름을 말하는 것을 할 수 없을 때 예외를 던지십시오.

아이디어는 예외가 무언가 잘못되었다는 것을 나타냅니다. 방법을 구현할 때는 방법이 올바르게 사용되는지 여부를 인식하는 것이 귀하의 책임이 아닙니다. 방법을 사용하는 코드가 예외를 포착하는지 여부는 귀하의 책임이 아니라 방법을 사용하는 사람의 책임입니다.

따라야 할 또 다른 규칙은 다음과 같습니다.

당신이 그것으로 무엇을하고 싶은지 알지 않는 한 예외를 포착하지 마십시오.

분명히, 당신은 시도에 정리 코드를 포함시켜야하지만 마침내 블록을 차단해야하지만, 그것을 잡기 위해서만 예외를 포착해서는 안됩니다. 그리고 당신은 예외를 조용히 삼키지 않아야합니다. 모든 예외를 포착하려는 경우가 있지만 (예 : C#에서 CATCH (예외)를 수행하여 (예 : 예외), 이들은 상당히 드물며 일반적으로 매우 구체적인 기술적 이유가 있습니다. 예를 들어 .NET 2.0 이상에서 스레드를 사용하는 경우 예외가 스레드에서 탈출하면 전체 응용 프로그램 도메인이 언로드됩니다. 그러나이 경우 최소한 예외 세부 정보를 오류로 기록하고 주석에 설명을 제공해야합니다.

일반적으로, 그리고 확실히 당신의 응용 프로그램의 초기 반복에서 ~하지 않다 예외를 잡으십시오. 종종 예외에서 회복하려면 어떤 종류의 비즈니스 규칙이 필요하며, 종종 해당 비즈니스 규칙이 귀하를 위해 정의되지 않습니다. 응용 프로그램을 죽이는 대신 예외를 "처리"하면 고객을위한 비즈니스 규칙을 발명 할 가능성이 높습니다. 안좋다.

그것을 잡기 위해 모든 예외를 잡는 일반적인 패턴은 내가 셀 수있는 것보다 더 많은 두통을 일으켰습니다. 일반적으로 누군가가 애플리케이션 전체에 일종의 일반적인 예외 처리 코드를 넣는 것이 불가피하게 버그를 숨기거나 원치 않는 동작을 만듭니다. (우연히, 잡고 재생하지 않는 것은 더 나쁩니다.)

그래서 대신 물어 보는 것이 좋습니다. "언제 예외를 포착해야합니까?"

확신하는. 예를 들어, 일부 바이트를 Java의 문자열에로드하려는 경우 :

try {
  String myString = new String(byteArray, "UTF-8");
} catch (UnsupportedEncodingException e) {
  // Platform doesn't support UTF-8?  What is this, 1991?
  throw new RuntimeExceptione(e);
}

이 경우 우아한 열화가 없으며 플랫폼은 단순히 원하는 작업을 지원할 수 없습니다. 초기화 에서이 조건을 확인할 수 있지만 String의 생성자는 여전히이 예외를 던지므로 처리해야합니다. 그 중 하나 또는 charset.forname ()을 사용하십시오. :)

여기에 문제가 있습니다 ...그것은 "레이어", "캡슐화" 또는 "낮은 결합"에 관한 것입니다.코드베이스의 어느 곳에서는 어떤 작업을 수행하는 메서드를 작성하고 있습니다.공개 방법이라고 가정해 보겠습니다.따라서 호출자에 대해 많은 것을 가정해서는 안 됩니다.오히려 전화를 건 사람이 누구인지, 전화를 건 사람이 어떤 상황에 있는지에 관계없이 해야 할 일만 수행하면 됩니다.

그리고 어떤 이유로든 작업을 완료할 수 없는 경우 발신자에게 "죄송합니다. 그렇게 할 수 없습니다. 그 이유는 다음과 같습니다"라고 말해야 합니다.예외는 호출자에게 이를 알려주는 훌륭한 메커니즘입니다(유일한 메커니즘은 아니지만 대부분의 경우 제가 본 최고의 메커니즘입니다).

그래서 예외를 던지면 잡을지 안 잡을지 알 수가 없습니다...공개 메소드를 노출하고 있으며 누가 이를 호출할지, 왜 호출할지 알 수 없기 때문입니다.

예외를 잡는 것은 "컨텍스트"의 작업입니다.예를 들어 예외를 발생시킬 수 있는 공개 메서드가 포함된 라이브러리를 작성한다고 가정해 보겠습니다.그런 다음 Windows Forms 앱에서 해당 라이브러리를 사용하고 있다고 가정해 보겠습니다.Windows Forms 앱은 예외를 포착하고 사용자에게 메시지 상자를 표시할 수 있습니다.

그러나 나중에 Windows 서비스에서 동일한 라이브러리를 사용할 수 있습니다.서비스는 예외를 포착하여 기록하고 원래 호출자에게 오류를 반환할 가능성이 높지만 추가 요청을 처리할 수 있도록 계속 실행됩니다.

따라서 예외는 발신자와 제공자 간의 계약상 합의와 같습니다.서비스 제공자는 "내가 그 일을 하든가 아니면 내가 할 수 없는 이유를 말해주겠다"고 말합니다.거기에서 당신이 하는 일은 당신 자신의 일입니다." 그러자 전화를 건 사람은 "좋아, 당신이 그 일을 할 수 없다면 이유를 말해 주세요. 그러면 그 경우에는 어떻게 할지 제가 결정하겠습니다."라고 말했습니다.

하지만 예외가 잡히지 않을 것이라는 것을 알고 예외를 던지고 싶은 경우가 있습니까?

수동으로 예외를 발생시키는 경우 대부분의 경우 해당 예외가 포착될지 알 수 없습니다.포착될 것이라는 것을 알고 있다면 처음부터 예외를 발생시키는 대신 직접 처리할 수 있습니다.

공평하게 말하면, 이는 부분적으로 수행 중인 프로그래밍 종류에 따라 달라지며 때로는 동일한 프로그래머가 라이브러리와 해당 라이브러리를 사용하는 코드를 모두 구축하는 경우도 있습니다.

예외를 포착하지 않겠습니까?

예상하지 못했거나 인식하지 못한 경우 예외가 발생할 수 있습니다.그러나 이를 제쳐두고 예외를 알고 있다고 가정하면 때로는 한 계층에서는 이에 대해 알고 있지만 다음 계층이 이를 처리하기에 더 적절한 위치라는 것을 알 수 있습니다.

응용 프로그램 유형에 따라 다릅니다. 예외가 실행 컨텍스트에 이르기까지 웹 애플리케이션은 계속 실행될 수 있습니다.

처리 할 수없는 수준에서 예외를 포착하는 경우 예외를 '던지기/재창조'하는 것이 일반적입니다. 그러나, 당신은 거의 항상 문제에 컨텍스트를 추가 할 것입니다. 최소한 더 높은 수준의 로깅을 추가하여 잡히고 재건되었다고 말합니다.

예를 들어

A 호출 B 호출 C (예외를 던지기)

b 캐치/재창조

잡기.

이 경우 B가 로깅을 추가하여 B 생성 및 오류를 던지고 C를 발생시키고 C를 생성하고 오류를 던질 수 있도록 로깅을 추가하려고합니다. 그러면 나중에 문제를 디버깅하고 수정하는 능력이 더 커집니다.

일반적으로 프로그램을 죽이는 예외를 거의 원하지 않을 것입니다. 모범 사례는 제외를 잡고 우아하게 빠져 나가는 것입니다. 이를 통해 현재 열린 정보를 저장하고 사용중인 리소스가 손상되지 않도록 릴리스 할 수 있습니다. 종료하려는 경우 치명적인 예외를 겪었을 때하고있는 일을 포함하는 자신만의 '코어 덤프'정보 보고서를 만들 수 있습니다.

예외를 죽이면 프로세스를 죽이면 맞춤 맞춤형 충돌 정보를 얻을 수있는 기회를 제거하고 사용자에게 친숙한 오류 메시지를 제공 한 다음 종료하는 부분을 건너 뛰는 것입니다.

따라서 항상 예외를 포착하는 것이 좋습니다. 자발적으로 프로그램에서 실행하는 것을 자발적으로 실행하지는 않습니다.

편집하다

도서관을 작성하는 경우 기능이 예외를 던지거나 예외가 될지 미리 선택해야합니다. 그러한 경우, 때때로, 당신은 예외를 던지고 전화 당사자가 그것을 잡을 것인지 전혀 모른다. 그러나이 경우 API가 함수가 예외를 던질 수 있다고 선언하는 한, 그것은 당신의 책임이 아닙니다. (나는 '예외를 던질 수있다'는 의미라는 단어를 찾고있다. 누구나 그것이 무엇인지 알고 있습니까? 하루 종일 나를 괴롭힐 것입니다.)

첫째, 예외를 포착하지 않는 것이 더 나은 상황이 절대적으로 있습니다.

때로는 예외가 때때로 귀하의 프로그램이 알려지지 않은 상태에 있음을 알 수 있습니다. 예외 유형을 감안할 때 이것이 본질적으로 사실 인 경우 여러 가지 예외가 있습니다. ㅏ NullReferenceException 본질적으로 "버그가 있습니다"라고 말합니다. 그리고 그러한 예외를 포착함으로써, 당신은 단기적으로 좋은 소리를 낼 수있는 버그를 숨길 수 있지만, 장기적으로는 그것을 고치는 것이 더 행복 할 것입니다. 제품은 충돌하지 않을 수 있지만 확실히 예상되는 동작은 없습니다.

그러나 이것은 우리 자신을 위해 발명 한 예외 유형에도 해당됩니다. 때로는 예외가 발생했다는 사실이 "불가능"해야한다는 사실은 "불가능"해야하지만 그 결과가 발생 했으므로 버그가 있습니다.

또한 예외를 포착 할 때 매우 중요한 일이 발생합니다. finally 시도 블록 내부의 전체 통화 스택에 대한 블록 (및 호출 호출)이 실행됩니다. 마침내 블록은 무엇을합니까? 글쎄, 무엇이든. 그리고 프로그램이 알려지지 않은 상태라면 나는 정말로 아무것. 디스크에서 귀중한 고객 데이터를 지울 수 있습니다. 그들은 더 많은 예외를 던질 수 있습니다. 메모리에서 데이터를 손상시켜 버그를 진단 할 수 없습니다.

따라서 예외가 알려지지 않은 상태를 나타내는 경우 더 이상 코드를 실행하고 싶지 않으므로 무엇을 하든지 예외를 포착하지 마십시오. 과거를 날리게하면 프로그램이 무해하게 종료되며 Windows 오류보고는 문제가 원래 감지되었을 때와 같이 프로그램의 상태를 포착 할 수 있습니다. 예외를 포착하면 더 많은 코드가 실행되므로 프로그램의 상태가 더 나빠집니다.

둘째, 잡히지 않을 것이라는 것을 알고 예외를 던져야합니까? 나는 그 질문이 재사용 가능한 방법의 본질을 오해한다고 생각합니다. 방법의 전체 아이디어는 다음과 같은 "계약"이 있다는 것입니다. 특정 매개 변수를 수락하고 특정 값을 반환하고 특정 조건에서 특정 예외를 던집니다. 그것이 계약입니다 - 그것은 그들이하는 일을 발신자에게 달려 있습니다. 일부 발신자의 경우 예외는 복구 가능한 조건을 나타낼 수 있습니다. 다른 발신자의 경우 버그를 나타낼 수 있습니다. 그리고 내가 위에서 말한 바에 따르면, 예외가 버그를 나타내는 경우, 잡히지 않아야합니다.

그리고 이것이 무엇을 의미하는지 궁금하다면 Microsoft Enterprise Library의 예외 처리 블록: 네, 꽤 깨졌습니다. 그들은 당신에게 말합니다 catch (Exception x) 그런 다음 귀하의 정책에 따라 재확인할지 여부를 결정하십시오. 너무 늦었습니다 finally 그 시점까지 블록이 이미 실행되었습니다. 그렇게하지 마십시오.

아마도 최종 사용자가 볼 수있는 곳 어디에서나 잡을 수없는 예외를 원하지 않을 것이지만, API (다른 프로그래머)의 클라이언트가 예외를 처리하는 방법을 결정하게하는 것이 종종 허용됩니다.

예를 들어, Java 클래스 라이브러리를 설계한다고 가정 해 봅시다. 문자열을 취하는 공개 방법을 노출시킵니다. 애플리케이션에서는 널 입력 값이 오류가 발생합니다. 오류를 직접 처리하는 대신 널 값을 확인한 다음 불법적 인 값을 던지는 것이 허용됩니다.

물론이 상황에서 방법 이이 예외를 던지는 것을 문서화해야합니다. 이 동작은 방법의 계약의 일부가됩니다.

그것은 당신이 '잡는 것'이 의미하는 바에 달려 있습니다. 무언가, 어딘가에는 결국 기본 OS이든 다른 것인지 여부에 관계없이 예외를 포착합니다.

우리는 개별 작업으로 구성된 작업 계획을 실행하는 워크 플로 시스템이 있습니다. 각 작업은 코드 단위를 실행합니다. 일부 예외는 코드에서 처리하고 싶지 않지만 외부 워크 플로 시스템이이를 잡을 수 있도록 스택을 던지기를 원하지 않습니다.

전체 응용 프로그램을 작성하는 경우 귀하의 이유는 자신의 것입니다. 나는 당신이 어디에 있는지 몇 가지 상황을 생각할 수 있습니다 ~할 것 같다 예외를 던지고 앱을 죽이게하고 싶지만 대부분은 그다지 좋은 이유가 아닙니다.

가장 좋은 이유는 일반적으로 디버깅 할 때입니다. 나는 무언가가 실패한 곳을 더 잘 알 수 있도록 디버깅하는 동안 예외를 비활성화합니다. 디버거가있는 컴퓨터에서 실행중인 경우 디버거에서 Exception Break를 켤 수 있습니다.

또 다른 가능한 이유는 예외가 발생한 후에도 계속해서 이해가되지 않거나 방해 할 수없는 데이터 손상 또는 더 나빠질 수 있기 때문입니다 (레이저 빔이있는 로봇을 생각하지만 응용 프로그램이 IMO를 처리하여 충돌하는 것입니다. 프로그램은 게으른 방법입니다).

자신이 사용하지 않는 API 코드 또는 프레임 워크 코드를 작성하는 경우 누군가가 귀하의 예외를 포착할지 전혀 모른다.

예, 개발자가 서비스/객체를 소비하여 "ur do1n it it it that that !!!!"라고 말할 수있는 유일한 기회입니다.

그것은 당신이 허용하고 싶지 않거나 "불가능한"것처럼 보이는 가능성을 제거합니다. 모든 예외를 포착하고 계속하는 앱은 혼돈으로 둘러싸인 벽으로 둘러싸인 정원입니다.

내가 일관된 방식으로 생각하는 것에서 어떻게 든 데이터를 처리하는 적당히 큰 시스템이 필요하다면.

그리고

라인을 따라 어딘가에, 나는 응용 프로그램의 상태가 일관되지 않았다는 것을 감지합니다.

그리고

시스템은 (아직) 불일치를 고치고 우아하게 회복하는 방법을 알지 못합니다.

그렇습니다. 가능한 한 많은 세부 사항으로 예외를 제외하고 데이터에 더 이상 해를 끼치 지 않도록 최대한 빨리 응용 프로그램이 죽게됩니다. 그것이 회복 될 수 있다면, 혼란을 덮기 위해 연약하게 시도함으로써 문제를 악화시키지 않는 것이 중요 할 것입니다.

나중에 노선을 따라, 불일치로 이어진 이벤트 체인이 더 잘 이해되면, 나는 더 높은 시설이 그 예외를 포착하고, 상태를 수리하고, 최소한의 중단을 계속할 수 있습니다.

도서관은 종종 방어 프로그래밍 점검을 기반으로 예외를 제외합니다. 애플리케이션 코드에 의해 발생해서는 안되는 조건이 발생할 경우. 응용 프로그램 코드는 종종 이러한 유효하지 않은 조건의 대부분이 결코 발생하지 않도록 작성되므로 예외는 절대로 던져지지 않으므로 포인트를 잡을 수 없습니다.

언어에 따라 (나는 C#이 아닌 C ++의 관점에서 대부분 생각하고 있으며, 차이점이 무엇인지 명확하지 않습니다) 실제로 흡입되지 않은 예외의 효과는 아마도 예외 전 며칠 동안 수행했던 것과 동일 할 것입니다. 발명되었습니다. 예를 들어, C 라이브러리의 방어 프로그래밍에 대한 일반적인 정책은 오류 메시지로 즉시 프로그램을 종료하는 것이 었습니다.

차이점은 예외 던지기가 가능하다면 (희망적으로 단위 테스트를 통해 발견 될 것입니다), 문제에서 복구 할 수있는 예외 핸들러를보다 건설적인 방식으로 추가하는 것이 비교적 쉽다는 것입니다. 도서관을 다시 작성하거나 응용 프로그램 코드에 복잡한 검사를 추가하여 예외 시도가 이루어지기 전에 조건이 발생할 수 없는지 확인하십시오.

나는 결코 잡히지 않은 예외 던지기를 많이 가지고 있습니다. 그것들은 모두 방어 목적을위한 것이며, 잡지는 예외는 예외적으로 나쁘지만, 지금까지 응용 프로그램 코드에서 고려하지 못한 오류 조건에 대해서는 개발 및 테스트 중에 만 발생합니다. 그리고 그것이 일어날 때, 수정이 어색 해지는 것은 드문 일입니다. 대규모 리팩토링이 필요하지 않으며, 응용 프로그램 코드가 오류 조건 검사와 크게 복잡 할 필요가 없습니다. 미안 해요, 데이브, 그렇게 할 수 없어요. " 전체 앱을 실패하지 않고.

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