오류 처리를 수행하는 현대적인 방법…


118

나는이 문제를 잠시 동안 숙고하고 있으며 끊임없이 경고와 모순을 발견하고 있기 때문에 누군가 다음과 같은 결론을 내릴 수 있기를 바랍니다.

오류 코드보다 예외를 선호

내가 아는 한, 업계에서 4 년간 일하면서 책과 블로그를 읽는 등 오류를 처리하는 가장 좋은 방법은 오류 코드 (반드시 오류 코드가 아니라 반드시 오류를 나타내는 유형).

그러나 이것은 나에게 모순되는 것처럼 보입니다 ...

구현이 아닌 인터페이스 코딩

커플 링을 줄이기 위해 인터페이스 또는 추상화로 코딩합니다. 우리는 인터페이스의 특정 유형과 구현을 모르거나 알고 싶어합니다. 그렇다면 어떤 예외를 잡아야하는지 어떻게 알 수 있습니까? 구현시 10 가지의 예외가 발생하거나 전혀 발생하지 않을 수 있습니다. 확실하게 예외를 발견하면 구현에 대한 가정을하고 있습니까?

그렇지 않으면-인터페이스는 ...

예외 사양

일부 언어에서는 개발자가 특정 메소드가 특정 예외를 처리한다고 언급 할 수 있습니다 (예 : Java는 throws키워드 사용 ). 호출 코드의 관점에서 보면 이것은 괜찮은 것 같습니다.

그러나-이것은 제안하는 것 같습니다 ...

새는 추상화

인터페이스에서 어떤 예외를 throw 할 수 있는지 지정해야하는 이유 구현에서 예외를 발생시킬 필요가 없거나 다른 예외를 발생시켜야하는 경우 어떻게해야합니까? 인터페이스 수준에서는 구현에서 어떤 예외를 throw할지 알 수있는 방법이 없습니다.

그래서...

결론적으로

소프트웨어 모범 사례와 모순되는 것처럼 예외가 선호되는 이유는 무엇입니까? 그리고 오류 코드가 너무 나쁘면 (그리고 오류 코드의 역으로 ​​팔 필요가 없다면) 다른 대안이 있습니까? 위에서 설명한 모범 사례의 요구 사항을 충족하지만 오류 코드의 반환 값을 확인하는 호출 코드에 의존하지 않는 오류 처리에 대한 현재의 최신 상태는 무엇입니까?


12
새는 추상화에 대한 당신의 주장을 얻지 못했습니다. 특정 메소드 던질 있는 예외를 지정하는 것은 인터페이스 사양의 일부입니다 . 리턴 값의 유형이 인터페이스 스펙의 일부인 것처럼. 예외는 함수의 "왼쪽에서"나오지 않지만 여전히 인터페이스의 일부입니다.
12

@deceze 인터페이스는 구현이 던질 수있는 것을 어떻게 설명 할 수 있는가? 타입 시스템에서 모든 예외를 던질 수 있습니다! 그리고 많은 언어들이 예외 사양을 지원하지 않는 것은 예외 사양을 제안합니다
RichK

1
메소드 자체가 다른 메소드를 사용하고 내부에서 예외를 포착하지 않으면 메소드가 던질 수있는 모든 다른 예외를 관리하는 것이 까다로울 수 있음에 동의합니다. 그 말은 모순이 아닙니다.
12

1
여기서 유출 된 가정은 코드가 인터페이스 경계를 ​​벗어날 때 예외를 처리 할 수 있다는 것입니다 . 실제로 무엇이 잘못되었는지에 대해 거의 알지 못한다는 점을 감안할 때 매우 가능성이 없습니다. 아는 것은 무언가 잘못되었고 인터페이스 구현이 그것을 처리하는 방법을 몰랐다는 것입니다. 더 나은 일을 할 가능성은보고하고 프로그램을 종료하는 것 외에는 좋지 않습니다. 또는 인터페이스가 올바른 프로그램 작동에 중요하지 않은 경우 무시하십시오. 인터페이스 계약에서 인코딩 할 수없고 인코딩해서는 안되는 구현 세부 사항.
Hans Passant

답변:


31

우선, 나는이 진술에 동의하지 않을 것입니다 :

오류 코드보다 예외를 선호

항상 그런 것은 아닙니다. 예를 들어 Objective-C를 살펴보십시오 (Foundation 프레임 워크 사용). NSError는 Java 개발자가 @Exception, @catch, @throw, NSException 클래스 등의 진정한 예외라고 부르는 것에도 불구하고 오류를 처리하는 데 선호되는 방법입니다.

그러나 많은 인터페이스가 예외를 제외하고 추상화를 유출하는 것은 사실입니다. 이것이 "예외"스타일 오류 전파 / 처리의 결함이 아니라고 생각합니다. 일반적으로 오류 처리에 대한 최상의 조언은 다음과 같습니다.

가능한 가장 낮은 수준의 오류 / 예외 처리

만약 그 규칙을 고수한다면 추상화에서 나온 "누설"의 양은 매우 제한적이며 억제 될 수 있다고 생각합니다.

메소드에 의해 발생 된 예외가 선언의 일부 여야하는지 여부에 대해서는 다음과 같이 생각합니다. 이 인터페이스에 의해 정의 된 계약의 일부입니다 .이 메소드는 A를 수행하거나 B 또는 C에 실패합니다.

예를 들어, 클래스가 XML 파서 인 경우 디자인의 일부는 제공된 XML 파일이 잘못되었음을 나타냅니다. Java에서는 일반적으로 발생할 것으로 예상되는 예외를 throws선언하고 메소드 선언 부분에 예외를 추가하여 수행합니다 . 반면에 파싱 알고리즘 중 하나가 실패한 경우 처리되지 않은 예외를 통과 할 이유가 없습니다.

모든 것이 한 가지로 요약됩니다 : 좋은 인터페이스 디자인. 인터페이스를 충분히 디자인하면 예외가 발생하지 않습니다. 그렇지 않으면, 당신을 귀찮게하는 것은 예외가 아닙니다.

또한 Java 제작자는 메소드 선언 / 정의에 예외를 포함시켜야 할 매우 강력한 보안상의 이유가 있다고 생각합니다.

마지막으로 에펠 탑과 같은 일부 언어에는 오류 처리를위한 다른 메커니즘이 있으며 단순히 던지기 기능이 포함되어 있지 않습니다. 여기서 루틴의 사후 조건이 충족되지 않으면 '예외'정렬이 자동으로 발생합니다.


12
"오류 코드에 대한 즐겨 찾기 예외"를 무시하면 +1입니다. 나는 예외가 실제로는 예외이고 규칙이 아닌 한 예외는 좋고 훌륭하다는 것을 배웠다. 조건이 참인지 여부를 판별하기 위해 예외를 발생시키는 메소드를 호출하는 것은 매우 나쁜 습관입니다.
Neil

4
@JoshuaDrake : 그는 확실히 틀 렸습니다. 예외와 goto는 매우 다릅니다. 예를 들어, 예외는 항상 같은 방향으로 진행됩니다. 당신이 정리를 위해 RAII를 사용하는 경우 둘째, 깜짝 예외으로부터 자신을 보호하는 것은 그것은에서 정리 보장, 정확히 C ++에서 예를 들어 건식과 같은 연습이다 모든 경우에, 다만 예외뿐만 아니라 모든 정상적인 제어 흐름을. 이것은 훨씬 더 안정적입니다. try/finally다소 비슷한 것을 성취합니다. 정리를 올바르게 보장하면 예외를 특별한 경우로 고려할 필요가 없습니다.
DeadMG

4
@JoshuaDrake 죄송합니다. Joel은 아직 멀었습니다. 예외는 goto와 동일하지 않으므로 항상 최소 한 단계 위로 호출 스택을 이동합니다. 위의 수준에서 오류 코드를 즉시 처리 할 수 ​​없으면 어떻게해야합니까? 또 다른 오류 코드를 반환 하시겠습니까? 오류가 발생하는 문제 중 일부는 무시할 수있어 예외를 던지는 것보다 더 나쁜 문제가 발생할 수 있다는 것입니다.
Andy

25
-1 "가장 낮은 수준의 오류 / 예외에 대한 처리"에 완전히 동의하지 않기 때문에-기간이 잘못되었습니다. 적절한 수준 의 오류 / 예외를 다루십시오 . 종종 그것은 훨씬 높은 수준이며,이 경우 오류 코드는 큰 고통입니다. 오류 코드보다 예외를 선호하는 이유는 오류 코드를 사용하여 중간 레벨에 영향을주지 않고 처리 할 레벨을 자유롭게 선택할 수 있기 때문입니다.
Michael Borgwardt

2
@Giorgio : 참조 artima.com/intv/handcuffs.html - 특히 2 페이지와 3
마이클 Borgwardt

27

예외 및 오류 코드가 오류 및 대체 코드 경로를 처리하는 유일한 방법은 아니라는 점에 유의하고 싶습니다.

마음 속에서 Haskell과 같은 접근 방식을 사용할 수 있습니다. 여기서 여러 생성자가있는 추상 데이터 유형을 통해 오류를 신호 할 수 있습니다 (차별 열거 형 또는 null 포인터를 생각하지만 형식이 안전하고 구문을 추가 할 가능성이 있음) 코드 흐름을 좋게 만드는 설탕 또는 도우미 함수).

func x = do
    a <- operationThatMightFail 10
    b <- operationThatMightFail 20
    c <- operationThatMightFail 30
    return (a + b + c)

operationThatMightfail은 Maybe에 싸인 값을 반환하는 함수입니다. 그것은 nullable 포인터처럼 작동하지만 do 표기법은 a, b 또는 c 중 하나라도 실패하면 모든 것이 null로 평가되도록합니다. (그리고 컴파일러는 실수로 NullPointerException이 발생하지 않도록 보호합니다)

또 다른 가능성은 오류 처리기 객체를 호출하는 모든 함수에 대한 추가 인수로 전달하는 것입니다. 이 오류 처리기는 전달할 함수에 의해 신호를받을 수있는 각 가능한 "예외"에 대한 방법을 가지고 있으며, 예외를 통해 스택을 되 감지 않아도 예외가 발생하는 경우이를 처리하기 위해 해당 함수에 의해 사용될 수 있습니다.

일반적인 LISP는이를 수행하며, 구문 지원 (암시 적 인수)과 내장 함수가이 프로토콜을 따르도록하여 실현 가능하게합니다.


1
정말 깔끔합니다. 대안에 대한 부분에 답변 주셔서 감사합니다 :)
RichK

1
BTW, 예외는 현대 명령형 언어에서 가장 기능적인 부분 중 하나입니다. 예외는 모나드를 형성합니다. 예외는 패턴 일치를 사용합니다. 예외 Maybe는 실제로 무엇을 배우지 않고도 적용 스타일을 모방하는 데 도움 이됩니다.
9000

최근에 SML에 관한 책을 읽고있었습니다. 옵션 유형, 예외 및 연속에 대해 언급했습니다. 조언은 정의되지 않은 사례가 다소 자주 발생할 것으로 예상되는 경우 옵션 유형 을 사용하고 정의되지 않은 사례가 거의 발생하지 않는 경우 예외를 사용하는 것이 었습니다.
Giorgio

8

그렇습니다. 예외로 인해 유출이 발생할 수 있습니다. 그러나 이와 관련하여 오류 코드가 더 나쁘지 않습니까?

이 문제를 처리하는 한 가지 방법은 인터페이스가 어떤 상황에서 어떤 예외를 발생시킬 수 있는지 정확하게 지정하고 구현이 필요한 경우 예외를 포착, 변환 및 다시 발생시켜 내부 예외 모델을이 사양에 매핑해야한다는 것을 선언하는 것입니다. "prefect"인터페이스를 원한다면 그렇게하세요.

실제로, 일반적으로 인터페이스의 논리적 일부이고 클라이언트가 파악하고 수행하려는 예외를 지정하는 것으로 충분합니다. 일반적으로 저수준 오류가 발생하거나 버그가 나타날 때 다른 예외가있을 수 있으며 클라이언트가 오류 메시지를 표시하거나 응용 프로그램을 종료하여 만 처리 할 수있는 것으로 일반적으로 이해됩니다. 최소한 예외는 여전히 문제 진단에 도움이되는 정보를 포함 할 수 있습니다.

실제로 오류 코드를 사용하면 거의 묵시적인 방식으로 정보가 손실 될 가능성이 훨씬 높아지고 앱이 일관성이없는 상태로 끝나는 것과 거의 동일한 결과가 발생합니다.


1
오류 코드가 누수 추상화를 유발할 수있는 이유를 이해하지 못합니다. 정상 반환 값 대신 오류 코드가 반환되고이 동작이 함수 / 방법의 사양에 설명되어 있으면 IMO에 누출이없는 것입니다. 아니면 내가 간과하고 있습니까?
조르지오

API가 구현에 구애받지 않는 동안 오류 코드가 구현에 고유 한 경우 오류 코드를 지정하고 반환하면 원치 않는 구현 세부 정보가 유출됩니다. 일반적인 예 : 파일 기반 및 DB 기반 구현을 사용하는 로깅 API. 전자는 "디스크 가득 참"오류가 있고 후자는 "호스트가 DB 연결을 거부했습니다"오류가있을 수 있습니다.
Michael Borgwardt

네가 무슨 말을 하려는지 알 겠어. 구현 특정 오류를보고하려는 경우 API가 구현에 무관심 할 수 없습니다 (오류 코드 또는 예외가 아님). 유일한 해결책은 "자원을 사용할 수 없음"과 같은 구현에 무관 한 오류 코드를 정의하거나 API가 구현에 무관심하지 않다고 결정하는 것입니다.
조르지오

1
@Giorgio : 그렇습니다. 구현에 구애받지 않는 API를 사용하면 구현 관련 오류를보고하기가 까다 롭습니다. 그럼에도 불구하고 (오류 코드와 달리) 여러 필드를 가질 수 있기 때문에 예외로 처리 할 수 ​​있습니다. 따라서 예외 유형을 사용하여 일반 오류 정보 (ResourceMissingException)를 제공하고 구현 별 오류 코드 / 메시지를 필드로 포함 할 수 있습니다. 두 세계의 최고 :-).
썰매 시간

그리고 BTW는 바로 java.lang.SQLException이하는 일입니다. 그것은이 getSQLState(일반) 및 getErrorCode(공급 업체 특정)을. 적절한 서브 클래스 만 가지고 있다면 ...
sleske

5

여기에 좋은 것들이 많이 있습니다. 우리는 정상적인 제어 흐름의 일부로 예외를 사용하는 코드를 조심해야한다고 덧붙이고 싶습니다. 때때로 사람들은 일반적인 경우가 아닌 어떤 것이 예외가되는 그 함정에 빠지게됩니다. 루프 종료 조건으로 사용되는 예외를 보았습니다.

예외는 "내가 처리 할 수없는 일이 발생했습니다. 어떻게해야할지 알아 내려면 다른 사람에게 나가야합니다." 유효하지 않은 입력을 입력하는 사용자는 예외가 아닙니다 (다시 요청하여 입력으로 로컬에서 처리해야 함).

내가 본 예외 사용의 또 다른 퇴행 사례는 첫 번째 응답이 "예외 발생"인 사람들입니다. 이것은 거의 항상 catch를 작성하지 않고 수행됩니다 (엄지 규칙 : catch를 먼저 작성한 다음 throw 문을 작성하십시오). 큰 응용 프로그램에서는 포착되지 않은 예외가 네더 영역에서 발생하여 프로그램을 폭발시킬 때 문제가됩니다.

나는 예외가 아니지만 몇 년 전의 싱글 톤처럼 보입니다 : 너무 자주 그리고 부적절하게 사용되었습니다. 그것들은 의도 된 용도에 완벽하지만 그 경우는 생각만큼 광범위하지 않습니다.


4

새는 추상화

인터페이스에서 어떤 예외를 throw 할 수 있는지 지정해야하는 이유 구현에서 예외를 발생시킬 필요가 없거나 다른 예외를 발생시켜야하는 경우 어떻게해야합니까? 인터페이스 수준에서는 구현에서 어떤 예외를 throw할지 알 수있는 방법이 없습니다.

아니. 예외 사양은 반환 및 인수 유형과 동일한 버킷에 있으며 인터페이스의 일부입니다. 해당 사양을 준수 할 수없는 경우 인터페이스를 구현하지 마십시오. 던지지 않으면 괜찮습니다. 인터페이스에서 예외를 지정하는 데 누출이 없습니다.

오류 코드가 잘못되었습니다. 그들은 끔찍하다. 매번 호출 할 때마다 수동으로 확인하고 전파해야합니다. 이것은 시작을 위해 DRY를 위반하고 오류 처리 코드를 크게 폭파시킵니다. 이 반복은 예외가 발생하는 것보다 훨씬 더 큰 문제입니다. 예외를 조용히 무시할 수는 없지만 사람들은 리턴 코드를 조용히 무시할 수 있습니다.


그래도 좋은 형태의 구문 설탕이나 도우미 메서드가있는 경우 오류 코드를 사용하는 것이 더 쉬울 수 있으며, 일부 언어에서는 컴파일러와 형식 시스템을 통해 오류 코드 처리를 잊지 않도록 보장 할 수 있습니다. 예외 인터페이스 부분에 관해서는 Java의 확인 된 예외의 악명 높은 혼란에 대해 생각하고 있다고 생각합니다. 언뜻보기에는 완벽하게 합리적인 아이디어처럼 보이지만 실제로는 고통스럽고 작은 문제가 많이 발생합니다.
hugomg

@missingno : 평소와 같이 Java는 확인 된 예외가 본질적으로 나쁘지 않기 때문에 끔찍한 구현을 가지고 있기 때문입니다.
DeadMG

1
@missingno : 확인 된 예외로 인해 어떤 종류의 문제가 발생할 수 있습니까?
조르지오

@Giorgio : 아직 작성되지 않은 다른 서브 클래스와 코드를 고려해야하기 때문에 메소드가 발생할 수있는 모든 종류의 예외를 예견하기는 매우 어렵습니다. 실제로 사람들은 모든 것에 시스템 예외 클래스를 재사용하거나 내부 예외를 자주 잡아서 다시 던져야하는 것과 같이 정보를 버리는 추악한 해결 방법으로 끝납니다. 또한 확인 된 예외가 언어에 익명 기능을 추가하려고 할 때 큰 장애물이라고 들었습니다.
hugomg

@missingno : Java의 AFAIK 익명 함수는 정확히 하나의 방법으로 익명 내부 클래스의 구문 설탕이므로 확인 된 예외가 왜 문제가되는지 이해가되지 않습니다 (그러나 주제에 대해 많이 알지 못합니다). 그렇습니다. 메서드가 어떤 예외를 던질 지 예측하기 어렵습니다. 따라서 IMO가 예외를 확인하는 것이 유용하므로 추측 할 필요가 없습니다. 물론 잘못된 코드를 처리하여 처리 할 수 ​​있지만 확인되지 않은 예외로도 수행 할 수 있습니다. 그러나 나는 논쟁이 상당히 복잡하고 솔직히 양쪽에 장단점이 있음을 알고 있습니다.
조르지오

2

예외 처리에는 자체 인터페이스 구현이있을 수 있습니다. 발생 된 예외 유형에 따라 원하는 단계를 수행하십시오.

디자인 문제에 대한 해결책은 두 가지 인터페이스 / 추상화 구현을하는 것입니다. 하나는 기능을위한 것이고 다른 하나는 예외 처리를위한 것입니다. 그리고 포착 된 예외 유형에 따라 적절한 예외 유형 클래스를 호출하십시오.

오류 코드의 구현은 예외를 처리하는 정통 방법입니다. 문자열 대 문자열 빌더의 사용법과 같습니다.


4
즉, 구현은 API에 정의 된 예외의 하위 클래스를 발생시킵니다.
Andrew cooke

2

IM-very-HO 예외는 경우에 따라 판단해야합니다. 제어 흐름을 깨 뜨리면 코드의 실제적이고 지각 된 복잡성이 증가하기 때문에 많은 경우에 불필요합니다. 함수 내에서 예외를 던지는 것과 관련된 토론을 제외하면 호출 경계를 통해 예외를 던지는 것을 제어하려는 경우 실제로 제어 흐름을 향상시킬 수 있습니다.

수신자가 제어 흐름을 중단하도록 허용하면 실질적인 이점이 제공되지 않을 수 있으며 예외를 처리하는 의미있는 방법이 없을 수 있습니다. 직접적인 예를 들어 Observable 패턴을 구현하는 경우 (C #과 같은 언어로 throws정의 가 명시 적이 지 않은 언어로 ), Observer가 제어 흐름이 충돌 할 경우 제어 흐름을 중단시킬 실제적인 이유는 없습니다. 그들의 물건을 다루는 의미있는 방법이 없습니다 (물론, 좋은 이웃은 관찰 할 때 던져서는 안되지만 아무도 완벽하지 않아야합니다).

위의 관찰은 느슨하게 결합 된 인터페이스로 확장 될 수 있습니다 (지시 한대로). 실제로 3-6 개의 스택 프레임을 들어온 후 잡히지 않은 예외가 다음 코드 중 하나에서 끝날 가능성이 높다고 생각합니다.

  • 예외 자체가 업 캐스트 된 경우에도 의미있는 방식으로 예외를 처리하기에는 너무 추상적입니다.
  • 일반 기능을 수행하고 있습니다 (메시지 펌프 또는 관찰 가능 장치와 같이 실패한 이유에 대해서는 신경 쓰지 않았습니다).
  • 구체적이지만 책임이 다르므로 걱정하지 않아도됩니다.

위의 사항을 고려할 때, throws시맨틱으로 인터페이스를 장식 하는 것은 인터페이스 계약을 통해 많은 호출자가 실패한 경우에만 관심을 가지기 때문에 기능상의 한계는 아닙니다.

나는 그것이 맛과 편리함의 문제가된다고 말하고 싶습니다. "예외"이후에 발신자와 수신자 모두에서 상태를 우아하게 복구하는 것이 중요합니다. 따라서 오류 코드를 이동하는 데 많은 경험이 있다면 C 배경에서) 또는 예외가 악으로 변할 수있는 환경에서 작업하는 경우 (C ++), 물건을 던지는 것이 예쁘고 깨끗한 OOP에 너무 중요하여 이전에 의지 할 수 없다고 생각하지 않습니다 불편한 패턴. 특히 SoC가 중단되는 경우.

이론적 인 관점에서, SoC-Kosher 예외 처리 방법은 직접 발신자가 대부분의 경우 이유가 아니라 실패한 것만 처리한다는 관찰에서 직접 파생 될 수 있다고 생각합니다. 수신자가 던지고 매우 가까운 사람 (2-3 프레임)이 업 캐스트 된 버전을 포착하고 실제 예외는 항상 특수 오류 처리기 (추적 만하더라도)에 가라 앉습니다.이 핸들러는 AOP가 편리합니다. 수 평일 가능성이 있습니다.


1

오류 코드보다 예외를 선호

  • 둘 다 공존해야합니다.

  • 특정 동작을 예상하면 오류 코드를 반환하십시오.

  • 동작을 예상하지 못한 경우 예외를 반환하십시오.

  • 예외 유형이 남아있는 경우 오류 코드는 일반적으로 단일 메시지와 연관되지만 메시지는 다를 수 있습니다

  • 오류 코드가 아닌 예외에는 스택 추적이 있습니다. 깨진 시스템을 디버깅하기 위해 오류 코드를 사용하지 않습니다.

인터페이스가 아닌 구현에 대한 코딩

이것은 JAVA에만 해당 될 수 있지만 인터페이스를 선언 할 때 해당 인터페이스의 구현으로 인해 발생할 수있는 예외를 지정하지 않으면 의미가 없습니다.

확실하게 예외를 발견하면 구현에 대한 가정을하고 있습니까?

이것은 전적으로 귀하에게 달려 있습니다. 매우 특정한 유형의 예외를 시도한 다음보다 일반적인 예외를 포착 할 수 있습니다 Exception. 예외가 스택을 전파 한 다음 처리하도록하지 않겠습니까? 또는 예외 처리가 "플러그 가능"측면이되는 측면 프로그래밍을 볼 수도 있습니다.

구현에서 예외를 발생시킬 필요가 없거나 다른 예외를 발생시켜야하는 경우 어떻게해야합니까?

왜 이것이 당신에게 문제가되는지 이해할 수 없습니다. 예, 절대 실패 또는 예외를 발생시키지 않는 구현이 하나 있고 지속적으로 실패하고 예외를 발생시키는 다른 구현이있을 수 있습니다. 이 경우 인터페이스에 예외를 지정하지 않으면 문제가 해결됩니다.

예외 대신 구현이 결과 객체를 반환하면 아무것도 변경됩니까? 이 개체에는 오류 / 실패와 함께 작업 결과가 포함됩니다. 그런 다음 해당 개체를 조사 할 수 있습니다.


1

새는 추상화

인터페이스에서 어떤 예외를 throw 할 수 있는지 지정해야하는 이유 구현에서 예외를 발생시킬 필요가 없거나 다른 예외를 발생시켜야하는 경우 어떻게해야합니까? 인터페이스 수준에서는 구현에서 어떤 예외를 throw할지 알 수있는 방법이 없습니다.

내 경험상, 오류를 수신하는 코드 (예외, 오류 코드 또는 기타를 통한 코드)는 일반적으로 오류의 정확한 원인을 신경 쓰지 않을 것입니다. 오류 (오류 대화 상자 또는 로그 종류); 이보고는 실패한 프로 시저를 호출 한 코드와 직교로 수행됩니다. 예를 들어,이 코드는 특정 오류를보고하는 방법 (예 : 메시지 문자열 형식)을 알고있는 일부 다른 코드에 오류를 전달하여 컨텍스트 정보를 첨부 할 수 있습니다.

물론, 어떤 경우에는이 되는 오류에 특정 의미를 첨부 할 필요가 다르게 오류가 발생하는에 따라 반응한다. 이러한 경우는 인터페이스 사양에 문서화해야합니다. 그러나 인터페이스에는 여전히 특별한 의미가없는 다른 예외를 던질 권리가 있습니다.


1

예외를 통해 오류보고 및 처리를 위해보다 체계적이고 간결한 코드를 작성할 수 있습니다. 오류 코드를 사용하려면 모든 호출 후 반환 값을 확인하고 예기치 않은 결과가 발생할 경우 수행 할 작업을 결정해야합니다.

반면에 나는 예외가 인터페이스를 호출하는 코드에 숨겨져 야하는 구현 세부 사항을 드러낸다는 것에 동의한다. 어떤 코드가 어떤 예외를 던질 수 있는지에 대한 선험을 알 수 없기 때문에 (예를 들어 자바에서와 같이 메소드 서명에서 선언되지 않는 한) 예외를 사용하여 코드의 다른 부분 사이에 매우 복잡한 암시 적 종속성을 도입합니다. 의존성을 최소화하는 원칙에 위배됩니다.

요약 :

  • 잡히지 않은 예외는 오류 코드보다 훨씬 더 눈에 잘 띄고 무시하기 어렵 기 때문에 예외는 더 깨끗한 코드와 테스트 및 디버깅에 대한보다 적극적인 접근 방식을 허용한다고 생각합니다 (곧 실패).
  • 반면에 테스트 중에 발견되지 않은 발견되지 않은 예외 버그는 프로덕션 환경에서 충돌 형태로 나타날 수 있습니다. 특정 상황에서이 동작은 허용되지 않으며이 경우 오류 코드를 사용하는 것이 더 강력한 방법이라고 생각합니다.

1
동의하지 않습니다. 잡히지 않은 예외는 응용 프로그램을 중단시킬 수 있지만 확인되지 않은 오류 코드도 발생할 수 있습니다. 예외를 올바르게 사용하면 잡히지 않는 유일한 것은 치명적인 것 (OutOfMemory와 같은)이되며, 이러한 경우에는 즉시 충돌하는 것이 최선의 방법입니다.
썰매 타기

오류 코드는 발신자 m1과 수신자 m2 간의 계약의 일부입니다. 가능한 오류 코드는 m2의 인터페이스에서만 정의됩니다. 예외를 사용하면 (자바를 사용하고 메소드 서명에서 모든 예외를 선언하지 않는 한) 호출자 m1과 m2가 재귀 적으로 호출 할 수있는 모든 메소드 사이에 내재 된 계약이 있습니다. 물론 반환 된 오류 코드를 확인하지 않는 것은 실수이지만 항상 가능합니다. 반면, 구현 방법을 모르는 경우 메소드에서 발생한 모든 예외를 항상 점검 할 수있는 것은 아닙니다.
조르지오

첫째 : 모든 예외를 검사 할 수 있습니다. "포켓몬 예외 처리"를 수행하십시오 (예 : 모두 catch Exception또는 심지어 Throwable동등하게 포착해야 함).
썰매 시간

1
실제로 API가 올바르게 설계되면 클라이언트가 의미있게 처리 할 수있는 모든 예외를 지정합니다. 이러한 예외는 구체적으로 파악해야합니다. 이들은 오류 코드와 동일합니다). 다른 예외는 "내부 오류"를 의미하며 응용 프로그램은 해당 하위 시스템을 종료하거나 적어도 종료해야합니다. 원한다면 이것을 잡을 수 있지만 (위 참조), 보통 거품을 내야합니다. "버블 링"은 예외 사용의 주요 이점입니다. 필요에 따라 더 멀리 또는 더 잘 잡을 수 있습니다.
sleske

-1

오른쪽 바이어스.

무시할 수 없으며 처리해야하며 완전히 투명합니다. 그리고 올바른 왼손잡이 오류 유형을 사용하면 Java 예외와 동일한 정보를 모두 전달합니다.

단점? 적절한 오류 처리 기능이있는 코드는 역겨워 보입니다 (모든 메커니즘에 해당).


이것은 이전 10 가지 답변에서 제시하고 설명한 점에 비해 실질적인 것을 제공하지 않는 것 같습니다. 왜 그런 것들로 2 살짜리 질문을 부딪
치는가

여기서 아무도 편향된 권리를 언급하지 않았다. hugomg는 haskell에 대해 자세히 이야기했지만 오류가 발생한 이유에 대한 설명이나 복구 방법과 콜백은 제어 흐름 설계에서 가장 큰 죄 중 하나입니다. 그리고이 질문은 Google에 나타났습니다.
Keynan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.