it-swarm-ko.tech

언제 예외를 던지나요?

내 응용 프로그램이 기대하지 않는 모든 조건에 대해 예외가 생성되었습니다. UserNameNotValidException, PasswordNotCorrectException 등.

그러나 그 조건에 대해 예외를 만들면 안된다는 말을 들었습니다. 내 UML에서 주 흐름에 대한 예외는 예외이므로 왜 예외가 아니어야합니까?

예외를 만드는 지침이나 모범 사례가 있습니까?

402
Kwan Cheng

내 개인적인 지침은 : 현재 코드 블록의 기본 가정이 잘못된 것으로 판명되면 예외가 발생합니다.

예제 1 : 임의의 클래스를 검사하고 해당 클래스가 List <>에서 상속되면 true를 반환하는 함수가 있다고 가정하십시오. 이 함수는 "이 개체는 List의 자손입니까?"라는 질문을합니다. 이 함수는 연산에 회색 영역이 없기 때문에 예외를 발생시키지 않아야합니다. 모든 단일 클래스는 List <>에서 상속되거나 상속되지 않으므로 항상 "yes"또는 "no"입니다.

예제 2 : List <>를 검사하고 길이가 50보다 크면 true를 반환하고 길이가 작 으면 false를 반환하는 다른 함수가 있다고 가정 해보십시오. 이 함수는 "이 목록에 50 개가 넘는 항목이 있습니까?"라는 질문을합니다. 그러나이 질문은 가정합니다. 주어진 대상이 목록이라고 가정합니다. 내가 NULL을 건네면 그 가정은 거짓입니다. 이 경우 함수가 반환하면 어느 한 쪽 참된 또는 거짓이면 자체 규칙을 어 기고 있습니다. 이 함수는 반환 할 수 없습니다 아무것도 질문에 올바르게 답변했다고 주장하십시오. 따라서 반환되지 않습니다-예외가 발생합니다.

이것은 "loaded question" 논리적 오류와 비슷합니다. 모든 기능은 질문을합니다. 입력이 주어지면 그 질문에 오류가 생기면 예외를 던집니다. 이 줄은 void를 반환하는 함수를 사용하여 그리기가 더 어렵지만 결론은 입력에 대한 함수의 가정이 위반되면 정상적으로 반환하는 대신 예외를 throw해야합니다.

이 방정식의 다른 측면은 다음과 같습니다. 함수에서 예외를 자주 발생시키는 경우 가정을 구체화해야합니다.

577
The Digital Gabeg

그것들은 정상적으로 일어날 일이기 때문입니다. 제어 흐름 메커니즘은 예외입니다. 사용자는 종종 암호를 잘못받습니다. 예외가 아닙니다. 예외는 UserHasDiedAtKeyboard 유형의 상황에서는 매우 드 물어야합니다.

279
blowdart

저의 작은 가이드 라인은 "Code complete"라는 훌륭한 책에 크게 영향을받습니다.

  • 무시해서는 안되는 사항에 대해 알리려면 예외를 사용하십시오.
  • 오류를 로컬에서 처리 할 수있는 경우 예외를 사용하지 마십시오
  • 예외가 나머지 루틴과 동일한 추상화 레벨에 있는지 확인하십시오.
  • 정말 예외에 대한 예외는 예약해야합니다.
61
Commander Keen

사용자 이름이 유효하지 않거나 암호가 올바르지 않은 경우 예외가 아닙니다. 이것들은 정상적인 작동 흐름에서 기대해야 할 것입니다. 예외는 정상적인 프로그램 작업의 일부가 아니며 드물다.

편집 : 메소드를 호출하는 것만으로 예외를 throw하는지 알 수 없기 때문에 예외 사용을 좋아하지 않습니다. 따라서 예외를 적절한 방식으로 처리 할 수없는 경우에만 예외를 사용해야합니다 ( "메모리 부족"또는 "컴퓨터가 작동 중"이라고 생각).

34
EricSchaefer

일반적으로 예측할 수없는 경우 예외를 사용하는 것이 좋습니다. 데이터베이스 연결, 디스크에 파일이없는 등의 예가 있습니다. 예측할 수있는 시나리오 (예 : 잘못된 비밀번호로 로그인하려는 사용자는 부울을 리턴하고 상황을 정상적으로 처리하는 방법을 알고있는 기능을 사용해야 함)를 사용해야합니다. 누군가가 암호를 잘못 입력하여 예외를 throw하여 갑자기 실행을 끝내고 싶지 않습니다.

25
japollock

다른 사람들은 사용자가 잘못 입력하면 정상적인 흐름으로 잘못된 로그인이 예상되므로 예외를 사용해서는 안된다고 제안합니다. 나는 동의하지 않으며 추론을 얻지 못한다. 파일을 여는 것과 비교해보십시오. 파일이 존재하지 않거나 어떤 이유로 사용할 수없는 경우 프레임 워크에서 예외가 발생합니다. 위의 논리를 사용하는 것은 Microsoft의 실수였습니다. 오류 코드를 반환해야합니다. 파싱, 웹 요청 등에도 동일합니다.

정상적인 흐름의 잘못된 로그인 부분을 고려하지 않습니다. 예외적입니다. 일반적으로 사용자는 올바른 비밀번호를 입력하고 파일이 존재합니다. 예외적 인 경우는 예외적이며 예외를 사용하는 것이 좋습니다. 스택의 n 레벨을 통해 반환 값을 전파하여 코드를 복잡하게 만드는 것은 에너지 낭비이며 코드가 지저분해질 수 있습니다. 가능한 가장 간단한 일을하십시오. 오류 코드를 사용하여 조기에 최적화하지 마십시오. 정의에 따른 예외적 인 일은 거의 발생하지 않으며 예외를 발생시키지 않으면 비용이 발생하지 않습니다.

23
Bjorn Reppen

예를 들어, 잘못된 암호를 제공하는 사용자가있는 경우 예외는 다소 비용이 많이 드는 영향입니다. 일반적으로 실패 플래그 나 다른 잘못된 표시기를 다시 전달하는 것이 좋습니다.

이는 예외 처리 방식, 실제 잘못된 입력 및 고유 한 중요 중지 항목은 예외이지만 로그인 정보는 실패하지 않기 때문입니다.

16
Mitchel Sellers

현재 상태에서 벗어날 수있는 방법이 없을 때만 예외를 throw해야한다고 생각합니다. 예를 들어 메모리를 할당하고 할당 할 메모리가없는 경우. 언급 한 경우 해당 상태에서 명확하게 복구하고 그에 따라 오류 코드를 호출자에게 다시 반환 할 수 있습니다.


이 질문에 대한 답변을 포함하여 "예외"상황에서만 예외를 처리해야한다는 충고가 많이 있습니다. 그것은 겉으로는 합리적이지만, 하나의 질문 ( "예외를 던져야 할 때")을 다른 주관적인 질문 ( "특별한 것")으로 대체하기 때문에 잘못된 조언이다. 대신 Herb Sutter의 조언을 따르십시오 (C++의 경우 Dr Dobbs 기사 언제 사용 방법 ). Andrei Alexandrescu, C++ 코딩 표준 ) : 다음과 같은 경우에만 예외를 throw합니다

  • 전제 조건이 충족되지 않거나 (일반적으로 다음 중 하나가 불가능 함)
  • 대안은 사후 조건을 충족시키지 못하거나
  • 대안은 불변성을 유지하지 못할 것입니다.

왜 이것이 더 낫습니까? 전제 조건, 사후 조건 및 변형에 대한 질문을 several 질문으로 바꾸지 않습니까? 이것은 몇 가지 연결된 이유로 더 좋습니다.

  • 사전 조건, 사후 조건 및 불변은 프로그램의 내부 특성 인 design 특성이지만 throw에 대한 결정은 구현 세부 사항입니다. 디자인과 구현을 따로 고려해야한다는 점을 명심해야하며, 방법을 구현하는 동안 디자인 제약 조건을 만족시키는 것을 만드는 것이 우리의 임무입니다.
  • 전제 조건, 사후 조건 및 변하지 않는 관점에서 생각해야합니다. 이는 only 가정의 호출자가해야한다고 가정하고 정확하게 표현되어 구성 요소 사이의 느슨한 결합을 가능하게합니다. 우리 프로그램의.
  • 그런 느슨한 결합은 필요한 경우 구현을 리팩토링 할 수 있습니다.
  • 사후 조건과 불변은 테스트 가능합니다. 사후 조건은 우리의 단위 테스트 코드가 확인 (어설 션) 할 수있는 조건이기 때문에 쉽게 단위 테스트 할 수있는 코드가됩니다.
  • 사후 조건으로 생각하면 자연스럽게 예외를 사용하기위한 자연적인 스타일 인 성공 사후 조건 인 디자인이 생성됩니다. 프로그램의 정상 ( "행복한") 실행 경로는 선형으로 배치되며 모든 오류 처리 코드는 catch 절로 이동됩니다.
14
Jon

예외 사용시기에 대한 강력하고 빠른 규칙은 없다고 말하고 싶습니다. 그러나 사용하거나 사용하지 않는 좋은 이유가 있습니다.

예외를 사용해야하는 이유 :

  • 일반적인 경우의 코드 흐름이 더 명확합니다.
  • 복잡한 오류 정보를 객체로 반환 할 수 있습니다 (참조로 전달 된 오류 "out"매개 변수를 사용하여 달성 할 수도 있음)
  • 언어는 일반적으로 예외 발생시 정리 정리를 관리 할 수있는 기능을 제공합니다 (C #에서는 RAII, C++에서는 RAII 사용).
  • 예외가 발생하지 않으면 실행 코드를 반환하는 것보다 때때로 더 빠를 수 있습니다.
  • Java에서는 확인 된 예외를 선언하거나 포착해야합니다 (이에 대한 이유 일 수 있음).

예외를 사용하지 않는 이유 :

  • 오류 처리가 간단한 경우 때때로 과잉입니다
  • 예외가 문서화되거나 선언되지 않은 경우 호출 코드에 의해 예외가 포착되지 않을 수 있는데, 이는 호출 코드가 리턴 코드를 방금 무시한 것보다 더 나쁠 수 있습니다 (애플리케이션 종료 대 자동 실패-시나리오에 따라 더 나빠질 수 있음)
  • C++에서 예외를 사용하는 코드는 예외 안전해야합니다 (던지지 않거나 잡을 수는 없지만 던지기 함수를 간접적으로 호출하더라도)
  • C++에서는 함수가 언제 발생할 수 있는지 알기가 어렵 기 때문에 예외 안전에 대해 편집증을 사용해야합니다.
  • 예외를 던지고 잡는 것은 일반적으로 반환 플래그를 확인하는 것보다 훨씬 비쌉니다.

일반적으로 C++ 또는 C #보다 Java에서 예외를 사용하는 경향이 더 높습니다. 예외를 선언하거나 선언하지 않은 예외는 기본적으로 함수의 공식 인터페이스의 일부라는 의견이 있기 때문입니다. 호출 코드를 끊습니다. Java IMO에서 그것들을 사용하는 가장 큰 장점은 호출자가 예외를 처리해야한다는 것을 알고 있으며, 이는 올바른 행동의 가능성을 향상시킵니다.

이로 인해 모든 언어에서 항상 공통 클래스에서 코드 또는 API 계층의 모든 예외를 파생하므로 호출 코드는 항상 모든 예외를 잡을 수 있습니다. 또한 API 또는 라이브러리를 작성할 때 (예 : 호출자가받는 예외를 인터페이스의 맥락에서 이해할 수 있도록 하위 계층에서 예외를 래핑 할 때) 구현별로 예외 클래스를 던지는 것은 나쁜 것으로 간주합니다.

Java는 일반적인 예외와 런타임 예외를 구별 할 수 없다는 점에 유의하십시오. 후자는 선언 할 필요가 없습니다. 오류가 프로그램의 버그의 결과라는 것을 알고있을 때만 런타임 예외 클래스를 사용합니다.

10
Robert

예외 클래스는 "일반"클래스와 같습니다. 필드와 조작이 다른 다른 유형의 객체가 "있는"경우 새 클래스를 작성합니다.

경험상 예외 수와 예외 세분화 간의 균형을 유지해야합니다. 메소드가 4-5 개 이상의 서로 다른 예외를 발생시키는 경우 일부 예외를 더 "일반적인"예외 (예 : "AuthenticationFailedException")로 병합하고 예외 메시지를 사용하여 무엇이 잘못되었는지 자세히 설명 할 수 있습니다. 코드가 각각을 다르게 처리하지 않는 한 많은 예외 클래스를 만들 필요가 없습니다. 그리고 그렇다면 오류가 발생한 열거 형을 반환해야 할 수도 있습니다. 이런 식으로 조금 더 깨끗합니다.

5
Shachar

루프 내에서 코드를 반복 실행하여 예외를 반복적으로 발생시키는 경우 예외를 던지는 것은 큰 N의 경우 속도가 느리기 때문에 좋은 것은 아닙니다. 이슈. BaseException 또는 이와 유사한 것으로 모두 상속되는 기본 예외가 있는지 확인하십시오. BaseException은 System.Exception을 상속하지만 모든 예외는 BaseException을 상속합니다. 예외 유형의 트리를 사용하여 유사한 유형을 그룹화 할 수도 있지만 과도하거나 과도하지 않을 수 있습니다.

따라서 짧은 대답은 상당한 성능 저하를 일으키지 않으면 (많은 예외를 던지지 않는 한 안됩니다) 계속하십시오.

5
Charles Graham

나는 거기에 japollock 방법에 동의합니다-당신이 수술의 결과에 대해 확실하지 않을 때 수락을 던집니다. API 호출, 파일 시스템 액세스, 데이터베이스 호출 등. 프로그래밍 언어의 "경계"를 지나갈 때마다.

추가하고 싶습니다. 표준 예외를 자유롭게 던지십시오. "다른"(무시, 이메일, 로그, Twitter 고래 그림 표시 등) 작업을 수행하지 않는 한 사용자 지정 예외를 신경 쓰지 마십시오.

3
dclaysmith

예외를 던지기위한 경험 법칙은 매우 간단합니다. 코드가 UNRECOVERABLE INVALID 상태가되면 그렇게합니다. 데이터가 손상되었거나 특정 시점까지 발생한 처리를 되돌릴 수없는 경우 종료해야합니다. 실제로 다른 무엇을 할 수 있습니까? 처리 로직은 결국 다른 곳에서 실패합니다. 어떻게 든 복구 할 수 있다면 예외를 throw하지 마십시오.

특별한 경우에 돈 인출을 수락하는 것과 같은 어리석은 일을 한 다음 사용자/암호를 확인 해야하는 경우 예외가 발생하여 잘못된 일이 발생했음을 알리고 추가 손상을 방지함으로써 프로세스를 종료해야합니다.

3
goran

나는 일반적으로 모든 근본주의가 지옥으로 이어진다 고 말하고 싶습니다.

확실히 예외 구동 흐름으로 끝나고 싶지는 않지만 예외를 피하는 것도 나쁜 생각입니다. 두 가지 접근법 사이의 균형을 찾아야합니다. 내가하지 않는 것은 모든 예외 상황에 대해 예외 유형을 만드는 것입니다. 생산적이지 않습니다.

내가 일반적으로 선호하는 것은 시스템 전체에서 사용되는 두 가지 기본 유형의 예외를 만드는 것입니다 : LogicalExceptionTechnicalException. 필요한 경우 하위 유형으로 구분할 수 있지만 일반적으로 필요하지는 않습니다.

기술 예외는 데이터베이스 서버가 다운되거나 웹 서비스에 대한 연결이 IOException을 발생시키는 등 예상치 못한 예외를 나타냅니다.

반면에 논리적 예외는 덜 심각한 오류 상황을 상위 계층 (일반적으로 일부 유효성 검사 결과)으로 전파하는 데 사용됩니다.

논리적 예외조차도 프로그램 흐름을 제어하기 위해 정기적으로 사용되는 것이 아니라 흐름이 실제로 끝나야하는 상황을 강조하기위한 것입니다. Java에서 사용되는 경우 두 예외 유형은 모두 RuntimeException 서브 클래스이며 오류 처리는 측면 지향적입니다.

따라서 로그인 예제에서 AuthenticationException과 같은 것을 생성하고 sernameNotExisting, PasswordMismatch 등과 같은 열거 형 값으로 구체적인 상황을 구별하는 것이 현명 할 수 있습니다. 예외 계층 구조가 크며 catch 블록을 유지 관리 가능한 수준으로 유지할 수 있습니다. 예외를 분류하고 사용자에게 전파 할 대상과 방법을 잘 알고 있기 때문에 일반적인 예외 처리 메커니즘을 쉽게 사용할 수 있습니다.

일반적인 사용법은 사용자 입력이 유효하지 않은 웹 서비스 호출 중에 LogicalException을 발생시키는 것입니다. 예외는 SOAPFault 세부 사항에 마샬링 된 다음 클라이언트에서 다시 예외에 대해 비 정렬 화되어 예외가 해당 필드에 올바르게 맵핑되므로 하나의 특정 웹 페이지 입력 필드에 유효성 검증 오류가 표시됩니다.

이것은 반드시 유일한 상황은 아닙니다. 예외를 던지기 위해 웹 서비스를 칠 필요는 없습니다. 예외 상황 (페일 패스트가 필요한 경우 등)에서 자유롭게 할 수 있습니다. 이는 모두 귀하의 재량에 달려 있습니다.

2
Petr Macek

예외는 비정상적인 동작, 오류, 실패 등의 이벤트에 적용됩니다. 기능적 동작, 사용자 오류 등은 대신 프로그램 로직으로 처리해야합니다. 잘못된 계정이나 암호는 로그인 루틴의 논리 흐름에서 예상되는 부분이므로 예외없이 이러한 상황을 처리 할 수 ​​있어야합니다.

2
Joe Skora

일반적으로 응용 프로그램에서 발생할 수있는 "예외"에 대해서는 예외를 throw하려고합니다.

귀하의 예에서 두 예외는 모두 암호/사용자 이름 유효성 검사를 통해 호출하는 것처럼 보입니다. 이 경우 누군가가 사용자 이름/비밀번호를 잘못 입력하는 것이 예외적이지 않다고 주장 할 수 있습니다.

그것들은 UML의 주요 흐름에 대한 "예외"이지만 처리 과정에서 더 많은 "분기"입니다.

Passwd 파일 또는 데이터베이스에 액세스하려고 시도했지만 액세스 할 수없는 경우 예외가되며 예외가 발생합니다.

2
Gord

첫째, API 사용자가 구체적이고 세분화 된 실패에 관심이 없다면 특정 예외를 갖는 것은 가치가 없습니다.

사용자에게 유용한 정보를 알 수없는 경우가 많으므로 더 좋은 방법은 특정 예외를 갖지만 공통 클래스 (예 : std :: exception 또는 C++의 파생물)에서 상속되도록하는 것입니다. 이를 통해 고객은 원하는 경우 특정 예외를, 또는 관심없는 경우보다 일반적인 예외를 포착 할 수 있습니다.

2
Jason Etheridge

예외 사용에 철학적 문제가 있습니다. 기본적으로 특정 시나리오가 발생할 것으로 예상하지만 명시 적으로 처리하는 대신 "어딘가에서"처리하도록 문제를 미루고 있습니다. 그리고 그 "다른 곳"이 어디에 있는지는 누구나 추측 할 수 있습니다.

2
Dan

내가 잡는 세 가지 유형의 조건이 있습니다.

  1. 입력이 잘못되었거나 누락 된 것은 예외가 아니어야합니다. 클라이언트 측 js와 서버 측 정규식을 모두 사용하여 속성을 감지하고 설정 한 후 메시지가있는 동일한 페이지로 다시 전달하십시오.

  2. AppException. 이것은 일반적으로 코드에서 감지하여 처리하는 예외입니다. 다시 말해, 이들은 당신이 기대하는 것입니다 (파일이 존재하지 않습니다). 로그를 작성하고 메시지를 설정 한 후 일반 오류 페이지로 다시 전달하십시오. 이 페이지에는 일반적으로 무슨 일이 있었는지에 대한 약간의 정보가 있습니다.

  3. 예기치 않은 예외. 이것들은 당신이 모르는 것입니다. 세부 사항과 함께이를 기록하고 일반 오류 페이지로 전달하십시오.

이것이 도움이되기를 바랍니다.

1
Michael

나를 위해 필요한 기술 또는 비즈니스 규칙이 실패하면 예외가 발생합니다. 예를 들어, 자동차 엔티티가 4 개의 타이어 배열과 연관되어있는 경우 ... 하나 이상의 타이어가 null 인 경우 ... 예외는 "NotEnoughTiresException"발생해야합니다. 로깅을 통한 의미. 우리가 그냥 흐름 제어를 시도하고 자동차의 instanciation을 방지하려는 경우 외에. 우리는 결코 문제의 원인을 찾지 못할 수도 있습니다.

1
Genjuro

간단한 대답은 작업이 불가능할 때마다 (비즈니스 논리를 위반하기 때문에 응용 프로그램 OR 때문에) 가능합니다. 메소드가 호출되어 메소드 작성을 수행 할 수없는 경우 예외를 처리하십시오. 좋은 예는 제공된 매개 변수를 사용하여 인스턴스를 만들 수없는 경우 생성자가 항상 ArgumentExceptions를 발생시키는 것입니다. 다른 예는 InvalidOperationException이며, 이는 다른 멤버 또는 클래스 멤버의 상태로 인해 조작을 수행 할 수 없을 때 발생합니다.

귀하의 경우, Login (username, password)과 같은 메소드가 호출 된 경우, 사용자 이름이 유효하지 않은 경우, 실제로 UserNameNotValidException을 발생시키는 것이 맞습니다. 또는 비밀번호가 틀린 경우 PasswordNotCorrectException을 발생시키는 것이 맞습니다. 제공된 매개 변수를 사용하여 사용자를 로그인 할 수 없습니다 (즉, 인증을 위반하기 때문에 불가능합니다). 비록 두 개의 예외가 ArgumentException에서 상속받을 수도 있습니다.

로그인 실패가 매우 일반적 일 수 있으므로 예외를 발생시키지 않으려면 한 가지 전략은 다른 실패를 나타내는 유형을 리턴하는 메소드를 작성하는 것입니다. 예를 들면 다음과 같습니다.

{ // class
    ...

    public LoginResult Login(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            return new UserInvalidLoginResult(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            return new PasswordInvalidLoginResult(user, password);
        }
        else
        {
            return new SuccessfulLoginResult();
        }
    }

    ...
}

public abstract class LoginResult
{
    public readonly string Message;

    protected LoginResult(string message)
    {
        this.Message = message;
    }
}

public class SuccessfulLoginResult : LoginResult
{
    public SucccessfulLogin(string user)
        : base(string.Format("Login for user '{0}' was successful.", user))
    { }
}

public class UserInvalidLoginResult : LoginResult
{
    public UserInvalidLoginResult(string user)
        : base(string.Format("The username '{0}' is invalid.", user))
    { }
}

public class PasswordInvalidLoginResult : LoginResult
{
    public PasswordInvalidLoginResult(string password, string user)
        : base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
    { }
}

대부분의 개발자는 예외로 인해 발생하는 오버 헤드로 인해 예외를 피해야합니다. 리소스를 사용하는 것이 좋지만 일반적으로 응용 프로그램 디자인을 희생하지는 않습니다. 아마 두 예외를 던지지 말라고 들었을 것입니다. 예외 사용 여부는 일반적으로 예외 발생 빈도로 요약됩니다. 상당히 흔하거나 기대할 수있는 결과라면 대부분의 개발자가 예외를 피하고 대신 리소스 소비로 인해 실패를 나타내는 다른 방법을 만드는 경우입니다.

다음은 Try () 패턴을 사용하여 방금 설명한 시나리오에서 예외 사용을 피하는 예입니다.

public class ValidatedLogin
{
    public readonly string User;
    public readonly string Password;

    public ValidatedLogin(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            throw new UserInvalidException(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            throw new PasswordInvalidException(password);
        }

        this.User = user;
        this.Password = password;
    }

    public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
    {
        if (IsInvalidUser(user) || 
            IsInvalidPassword(user, password))
        {
            return false;
        }

        validatedLogin = new ValidatedLogin(user, password);

        return true;
    }
}
1
core

내 생각에 근본적인 질문은 조건이 발생하면 호출자가 정상적인 프로그램 흐름을 계속하기를 원할지 여부입니다. 모르는 경우 별도의 doSomething 및 trySomething 메소드를 사용하십시오. 전자가 오류를 리턴하고 후자가 그렇지 않은 경우 또는 예외가 실패 할 경우 예외를 처리해야하는지 여부를 표시하는 매개 변수를 승인하는 루틴이 있습니다). 원격 시스템에 명령을 보내고 응답을보고하는 클래스를 고려하십시오. 특정 명령 (예 : 재시작)으로 인해 원격 시스템이 응답을 보내지 만 일정 시간 동안 응답하지 않습니다. 따라서 "ping"명령을 전송하여 원격 시스템이 예외가 발생하지 않으면 예외를 발생시키지 않고 적절한 시간 내에 응답하는지 여부를 확인할 수 있으면 유용합니다 (호출자는 처음 몇 " ping "시도는 실패하지만 결국에는 작동합니다). 반면에 다음과 같은 일련의 명령이있는 경우 :

 exchange_command ( "open tempfile"); 
 exchange_command ( "tempfile 데이터 쓰기 {whatever}"); 
 exchange_command ( "tempfile 데이터 쓰기 {whatever}"); 
 exchange_command ( "임시 파일 데이터 쓰기 {whatever}"); 
 exchange_command ( "임시 파일 데이터 쓰기 {whatever}"); 
 exchange_command ( "close tempfile"); 
 exchange_command ( "임시 파일로 임시 파일 복사"); 

전체 시퀀스를 중단하는 작업의 실패를 원할 것입니다. 각 작업의 성공 여부를 확인할 수 있지만 명령이 실패하면 exchange_command () 루틴에서 예외를 발생시키는 것이 더 도움이됩니다.

실제로, 위 시나리오에서 여러 가지 실패 처리 모드를 선택하는 매개 변수를 갖는 것이 도움이 될 수 있습니다. 예외를 던지지 말고, 통신 오류에 대해서만 예외를 던지거나, 명령이 "성공을 리턴하지 않는 경우 예외를 던지십시오. 표시.

1
supercat

예외 발생을 피하는 주된 이유는 예외 발생과 관련된 많은 오버 헤드가 있기 때문입니다.

아래 기사에서 언급 한 한 가지 예외는 예외적 인 조건과 오류에 대한 예외입니다.

잘못된 사용자 이름은 반드시 프로그램 오류 일 필요는 없지만 사용자 오류입니다 ...

다음은 .NET 내의 예외에 대한 적절한 시작점입니다. http://msdn.Microsoft.com/en-us/library/ms229030 (VS.80) .aspx

1
Sam

보안은 다음과 같은 예와 관련이 있습니다. 공격자에게 사용자 이름이 존재하지만 암호가 잘못되었음을 알리지 않아야합니다. 공유 할 필요가없는 추가 정보입니다. "사용자 이름 또는 비밀번호가 잘못되었습니다"라고 말합니다.

1
anon

예외가 발생하면 스택이 풀리고 성능에 약간의 영향을 미칩니다 (현대 관리되는 환경이 개선되었습니다). 중첩 된 상황에서 여전히 예외를 반복적으로 발생시키고 포착하는 것은 나쁜 생각입니다.

아마도 그보다 더 중요한 예외는 예외적 인 조건에 대한 것입니다. 코드의 가독성을 떨어 뜨리므로 일반적인 제어 흐름에는 사용하면 안됩니다.

1
Arno

예외가 적절한 지 결정할 때 고려해야 할 몇 가지 유용한 사항 :

  1. 예외 후보가 발생한 후 실행하려는 코드 레벨, 즉 호출 스택 계층을 해제해야하는 계층 수 일반적으로 예외가 발생하는 위치에 최대한 가깝게 예외를 처리하려고합니다. 사용자 이름/암호 유효성 검사의 경우 일반적으로 예외가 발생하지 않고 동일한 코드 블록에서 오류를 처리합니다. 따라서 예외는 적절하지 않을 수 있습니다. (OTOH, 세 번의 로그인 시도 실패 후 제어 플로우가 다른 곳으로 이동할 수 있으며 여기서 예외가 적절할 수 있습니다.)

  2. 이 이벤트가 오류 로그에 표시됩니까? 모든 예외가 오류 로그에 기록되는 것은 아니지만 오류 로그의이 항목이 유용한 지 여부를 묻는 것이 유용합니다.

0
Mike Kantor

예외에는 두 가지 주요 클래스가 있습니다.

1) 시스템 예외 (예 : 데이터베이스 연결 유실) 또는 2) 사용자 예외. (예 : 사용자 입력 확인, '비밀번호가 잘못되었습니다')

내 자신의 사용자 예외 클래스를 만드는 것이 도움이되었고 사용자 오류를 던지기를 원할 때 다르게 처리하고 싶을 때 (즉, 사용자에게 리소스 오류가 표시됨) 주 오류 처리기에서해야 할 일은 객체 유형을 확인하는 것입니다. :

            If TypeName(ex) = "UserException" Then
               Display(ex.message)
            Else
               DisplayError("An unexpected error has occured, contact your help  desk")                   
               LogError(ex)
            End If
0
Crusty

"PasswordNotCorrectException"은 예외 사용에 대한 좋은 예가 아닙니다. 비밀번호를 잘못 입력 한 사용자는 예상되므로 IMHO도 예외는 아닙니다. 니스 오류 메시지를 표시하여 복구 할 수도 있으므로 유효성 검사 일뿐입니다.

처리되지 않은 예외는 결국 실행을 중지시킵니다. false, null 또는 오류 코드를 반환하는 경우 프로그램의 상태를 모두 직접 처리해야합니다. 어딘가에서 조건을 확인하는 것을 잊어 버린 경우 프로그램이 계속 잘못된 데이터로 실행되고 what 발생한 및 where를 알아내는 데 어려움을 겪을 수 있습니다.

물론 빈 catch 문에서도 동일한 문제가 발생할 수 있지만 적어도 그 점을 발견하는 것이 더 쉽고 논리를 이해하지 않아도됩니다.

따라서 경험적으로 볼 때 :

원하지 않는 곳이나 단순히 오류를 복구 할 수없는 곳에서 사용하십시오.

0
DanMan

해당 조건에 대해 약간의 일반적인 예외를 사용할 수 있습니다. 예를 들어 ArgumentException은 메소드에 대한 매개 변수에 문제가있을 때 사용됩니다 (ArgumentNullException 제외). 일반적으로 LessThanZeroException, NotPrimeNumberException 등과 같은 예외는 필요하지 않습니다. 메소드의 사용자를 생각하십시오. 특히 처리하려는 조건의 수는 메소드에서 발생시켜야하는 예외 유형의 수와 같습니다. 이런 식으로, 당신은 당신이 가질 세부적인 예외를 결정할 수 있습니다.

그건 그렇고, 항상 라이브러리 사용자가 예외를 피할 수있는 몇 가지 방법을 제공하십시오. TryParse는 좋은 예입니다. int.Parse를 사용하지 않고 예외를 잡을 필요가 없습니다. 귀하의 경우 사용자 이름이 유효하거나 암호가 올바른지 확인하는 몇 가지 방법을 제공하여 사용자 (또는 귀하)가 많은 예외 처리를 수행하지 않아도 될 수 있습니다. 이것은 더 읽기 쉬운 코드와 더 나은 성능을 기대합니다.

0
Serhat Ozgel

궁극적으로 예외 처리 또는 상태 코드 반환과 같은 자체 홈 메커니즘을 통해 이와 같은 응용 프로그램 수준 오류를 처리하는 것이 더 도움이되는지 결정해야합니다. 나는 어느 것이 더 좋은지에 대한 단단하고 빠른 규칙이 없다고 생각하지만, 다음을 고려할 것입니다.

  • 누가 당신의 코드를 부르고 있습니까? 이것은 일종의 공개 API입니까, 아니면 내부 라이브러리입니까?
  • 어떤 언어를 사용하고 있습니까? 예를 들어 Java 인 경우 (확인 된) 예외를 throw하면 무시할 수있는 반환 상태가 아니라 호출자가이 오류 조건을 처리하는 데 명시적인 부담이 가해집니다. 좋거나 나쁠 수 있습니다.
  • 동일한 응용 프로그램의 다른 오류 조건은 어떻게 처리됩니까? 호출자는 시스템의 다른 것과 달리 특유의 방식으로 오류를 처리하는 모듈을 다루기를 원하지 않습니다.
  • 문제가되는 일상 생활에서 얼마나 많은 일이 잘못 될 수 있으며, 어떻게 다르게 처리 될 것입니까? 다른 오류를 처리하는 일련의 catch 블록과 오류 코드의 스위치 간의 차이점을 고려하십시오.
  • 반환해야 할 오류에 대한 구조화 된 정보가 있습니까? 예외를 던지면 상태를 반환하는 것보다이 정보를 더 잘 배치 할 수 있습니다.
0
eli