효율적인 시도 / 캐치 블록 사용법?


21

캐치 블록을 사용하여 논리를 작성해야합니까 (예 : 흐름 제어 등 처리)? 아니면 예외를 던지기 위해? 코드의 효율성 또는 유지 관리에 영향을 줍니까?

catch 블록에 쓰기 로직의 부작용 (있는 경우)은 무엇입니까?

편집하다:

catch 블록 내부에 논리를 작성한 Java SDK 클래스를 보았습니다. 예를 들어 ( java.lang.Integer클래스 에서 가져온 스 니펫 ) :

        try {
            result = Integer.valueOf(nm.substring(index), radix);
            result = negative ? new Integer(-result.intValue()) : result;
        } catch (NumberFormatException e) {
            String constant = negative ? new String("-" + nm.substring(index))
                                       : nm.substring(index);
            result = Integer.valueOf(constant, radix);
        }

EDIT2 :

나는 예외 내에서 예외적 인 경우의 논리를 작성하는 이점으로 계산 하는 자습서를 진행 했습니다.

예외를 사용하면 코드의 주요 흐름을 작성하고 예외적 인 경우를 처리 할 수 ​​있습니다.

캐치 블록에 로직을 쓸 때와 그렇지 않을 때 구체적인 지침이 있습니까?


12
@ 코더 나는 당신이 약간 지나치게 일반화한다고 생각합니다. 특히 많은 기존 API를 사용하면 피할 수 없습니다.
코드 InChaos

8
@Coder : Java 예외는 종종 합법적 인 코드 흐름의 일부인 문제를 알리는 메커니즘으로 사용됩니다. 예를 들어, 파일을 열려고하는데 실패하면 Java 라이브러리는 파일을 여는 API에는 오류를 반환하는 다른 메커니즘이 없기 때문에 예외를 발생시켜 알려줍니다.
JeremyP

4
@ 코더에 따라 다릅니다. IO를 수행 할 때 또는 거의 항상 올바르게 형식이 지정된 복잡한 데이터를 구문 분석 할 때 오류를 나타내는 예외를 던지면 코드가 훨씬 깨끗해집니다.
코드 인 카오스

1
@Coded 네, execption은 요청받은 것을 할 수 없다는 것을 알려주는 메소드입니다. 그러나 흐름 제어에는 예외를 사용해서는 안되므로 C #에는 던지지 않는 int.TryParse 메서드가 있습니다.
Andy

1
@ 코더 : 그것은 완전히 쓰레기입니다. 한 수준의 코드에서 예외적 인 것은 다른 단계에서 예외적이지 않을 수도 있으며, 예를 들어 계속하기 전에 오류를 표시하거나 정보를 추가하거나 디버그하려는 경우가 있습니다.
DeadMG

답변:


46

인용 한 예는 API 디자인이 좋지 않기 때문입니다 (문자열을 구문 분석하고 예외를 포착하는 것을 제외하고 String이 유효한 정수인지 확인하는 확실한 방법은 없습니다).

기술적 인 수준에서 throw 및 try / catch는 제어 흐름 구조로 , 호출 스택을 더 이상 증가시킬 수 있습니다. 호출 스택을 뛰어 넘으면 소스에서 서로 가깝지 않은 코드를 암시 적으로 연결 하므로 유지 관리좋지 않습니다 . 따라서 필요할 때만 사용해야하며 대안이 더 나쁩니다. 대안이 더 나쁘다 널리 경우 오류 처리입니다 (필요 확인하고 수동으로 호출 스택의 각 레벨을 통과 할 특별한 리턴 코드).

대안이 더 나쁜 경우 (그리고 실제로 모든 것을 신중하게 고려한 경우) 제어 흐름에 throw and try / catch를 사용하는 것이 좋습니다. 도그마는 판단을위한 좋은 대안이 아닙니다.


1
+1, 좋은 지적. 오류 메시지 준비 및 오류 로깅과 같은 일부 처리가 catch에서 유효 할 수 있다고 생각합니다. db 연결 및 (.NET) COM 참조와 같은 고가의 자원을 확보하면 최종 블록에 추가 될 수 있습니다.
NoChance

@EmmadKareem 리소스 해제에 대해 생각했지만 일반적으로 오류 상황이 없어도 언젠가는 해제해야합니다. 따라서 당신은 자신을 반복 할 수 있습니다. 물론 로그 메시지를 준비하는 것은 허용됩니다.
scarfridge

@MichaelBorgwardt API 디자인이 그렇게 나쁘지는 않다고 생각합니다 (더 좋을 수도 있지만). 유효하지 않은 문자열을 구문 분석하는 것은 분명히 오류 조건이므로 언급 한 "일반적으로 허용되는 사례"입니다. 동의, 문자열이 구문 상 올바른지 여부를 결정하는 방법이 유용합니다 (이곳이 더 좋을 수 있습니다). 그러나 실제 구문 분석 전에 모든 사람 이이 메소드를 호출하도록 강요하는 것은 불가능하며 오류를 처리해야합니다. 실제 결과와 오류 코드를 혼합하는 것은 불편하므로 여전히 예외가 발생합니다. 그러나 런타임 예외 일 수 있습니다.
scarfridge

3
마지막 문장 +1
FrustratedWithFormsDesigner

2
@scarfridge : 난 당신과 완전히 동의합니다 :) 부울 반환 isInteger (String) 메서드가 없다는 것은 "빈약 한 API 디자인"을 의미하는 것입니다
Michael Borgwardt

9

이것은 언어와 패러다임에 의존하는 경향이 있습니다.

내 작업의 대부분은 Java (및 때로는 C ++)로 수행됩니다. 예외적 인 상황에서만 예외를 사용하는 경향이 있습니다. Java의 예외 성능 오버 헤드에 대해 Stack Overflow에 대한 몇 가지 질문 이 있으며 , 알 수 있듯이 정확하게 무시할 수는 없습니다. 코드의 가독성 및 유지 관리 성과 같은 다른 문제도 있습니다. 올바르게 사용하면 예외가 오류 처리를 해당 구성 요소에 위임 할 수 있습니다.

그러나 파이썬에서는 권한이 지배하는 것보다 용서를 구하는 것이 더 쉽다는 생각이 있습니다. 파이썬 커뮤니티에서는이를 EAFP 라고하며 , C 스타일 언어의 " LBYL (look before you leap)" 접근 방식 과 대조 됩니다.


2
예외와 함께 오버 헤드를 언급하면 ​​+1입니다. .NET을 수행하고 (적어도 내 컴퓨터에서는) 다른 정상적인 작업과 비교하여 경우에 따라 예외가 발생할 때조차 느낄 수 있습니다.
NoChance

2
@EmmadKareem 디버거가 연결된 경우에만 해당됩니다. 디버거없이 초당 수천 개를 던질 수 있습니다.
코드 InChaos

@CodeInChaos, 맞습니다. 어떻게 알 수 있을까요, 나는 런타임에 절대로 얻을 수없는 깔끔한 코드를 작성합니다 :)
NoChance

@EmmadKareem 네트워크 응용 프로그램을 작성하는 방법에 따라 연결 또는 프로토콜 오류가 예외로 처리됩니다. 사소한 DoS 공격을 피하기 위해 그러한 애플리케이션에서는 예외가 신속해야합니다.
코드 InChaos

@CodeInChaos, 이것은 알아두면 좋습니다. 나는 나의 마지막 코멘트에서 농담을하고 있었다.
NoChance

9

시도 / 캐치 블록에 대해 생각하는 가장 좋은 방법은 아닙니다. try / catch 블록을 생각하는 방법은 다음과 같습니다. 실패가 발생했습니다.이 특정 실패를 처리하기에 가장 좋은 위치는 어디입니까? 그것은 다음 줄의 코드 일 수도 있고, 콜 체인보다 20 레벨 높을 수도 있습니다. 어디에 있든, 그것이 있어야 할 곳입니다.

catch 블록이 수행하는 작업은 오류와 수행 할 수있는 작업에 따라 다릅니다. 때로는 무시할 수 있습니다 (불량한 데이터가없는 스크래치 파일 삭제 실패) 때로는 함수 반환 값을 true 또는 false (java의 int parse 메소드)로 설정하는 데 사용되며 때로는 프로그램을 종료합니다 . 그 모든 것은 오류에 달려 있습니다.

이해해야 할 중요한 부분은 catch block ==입니다.이 문제를 해결하는 방법을 알고 있습니다.


6

캐치 블록은 예외 처리에만 사용되어야하며 제어 흐름에는 절대 적용되지 않아야합니다. 흐름을 관리하기 위해 예외를 사용하려는 상황에서는 사전 조건을 확인하는 것이 좋습니다.

예외가있는 플로우 처리는 느리고 의미 상 올바르지 않습니다.


4
나는 당신이 무슨 말을하는지 알고 있지만 예외가하는 모든 것은 프로그램 흐름을 처리하는 것뿐입니다. 예외적 인 오류 흐름을 제어하는 ​​데만 사용해야한다는 것입니다.
Max

캐치 블록에 로직을 작성할 때와 그렇지 않을 때 구체적인 지침이 없습니까?
HashimR

4
Java의 Number 파서 및 텍스트 포맷터는 문제가있는 예외 사용의 유명한 예입니다. 전제 조건 (문자열이 구문 분석 가능한 숫자를 나타냄)을 확인하는 유일한 합리적인 방법은 구문 분석을 시도하는 것입니다. 실제로? 의미 상 부정확 한 것으로 간주 되더라도 예외를 잡아서 플로우를 관리해야합니다.
Joonas Pulakka

@JoonasPulakka 나는 WRT 귀하의 코멘트 생각 번호 파서 및 텍스트 포맷터의 이 질문에 풀 사이즈 대답 자격
모기

5

캐치 블록을 사용하여 논리를 작성해야합니까 (예 : 흐름 제어 등 처리)? 아니면 예외를 던지기 위해? 코드의 효율성 또는 유지 관리에 영향을 줍니까?

먼저, "예외가 예외적 인 조건에 사용되어야한다는"개념을 잊어 버리십시오. 또한 수용 할 수없는 성능을 발휘하는 코드가 있고 문제가있는 위치를 파악할 때까지 효율성에 대한 걱정을 중단하십시오.

조건없이 작업이 간단한 순서로 수행되는 경우 코드를 이해하는 것이 가장 쉽습니다. 예외는 정상 흐름에서 오류 점검을 제거하여 유지 보수성을 향상시킵니다. 실행이 99.9 %의 시간 또는 50 %의 시간 또는 20 %의 정상적인 흐름을 따르는 지 여부는 중요하지 않습니다.

함수가 값을 리턴 할 수 없거나 프로 시저가 예상 조치를 완료 할 수 없거나 생성자가 사용 가능한 오브젝트를 생성 할 수없는 경우 예외를 처리하십시오. 이를 통해 프로그래머는 함수가 항상 사용 가능한 결과를 리턴하고 프로시 저는 항상 요청 된 조치를 완료하며 생성 된 오브젝트는 항상 사용 가능한 상태에 있다고 가정 할 수 있습니다.

예외 처리 코드에서 가장 큰 문제는 프로그래머가 시도 / 캐치 블록을 작성해서는 안된다는 것입니다. 예를 들어, 대부분의 웹 응용 프로그램에서 데이터베이스 요청에 예외가 발생하면 컨트롤러에서 수행 할 수있는 작업이 없습니다. 최상위 레벨의 하나의 일반 catch 절이면 충분합니다. 그런 다음 컨트롤러 코드는 디스크가 충돌했거나 데이터베이스가 오프라인 또는 기타 가능성을 무시할 수 있습니다.


1

캐치 블록은 코드 논리를 작성하는 데 사용해서는 안됩니다. 오류 처리에만 사용해야합니다. 예를 들어 (1) 할당 된 리소스를 정리하고 (2) 유용한 메시지를 인쇄하고 (3) 정상적으로 종료합니다.

예외가 남용되어 바람직하지 않은 goto결과를 초래할 수 있다는 것은 사실입니다 . 그러나 이것이 쓸모없는 것은 아닙니다. 올바르게 사용 하면 코드의 여러 측면을 향상시킬 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.