예외가 강력한 디버깅 방법 인 이유는 다음 세 가지 질문에 대답하기 때문입니다.
1. 무엇이 잘못 되었습니까?
2. 어디서 실수를 했습니까?
3. 왜 뭔가 잘못 되었습니까?
예외를 효과적으로 사용하는 경우, 예외 유형은 "무엇을 던지고, 예외 스택 추적"이 어디에 있는지 "응답하고, 예외 정보가"왜 "에 응답하고, 예외가 위의 모든 질문에 답하지 않으면, 당신은 그것들을 잘 사용하지 않을 수 있습니다.
디버깅 중 좋은 예외 사용을 극대화하는 데 도움이되는 세 가지 원칙이 있습니다. 이 세 가지 원칙은 다음과 같습니다.
1. 구체적이고 명확합니다
2. 일찍 던져
3. 지연 캡처
효과적인 예외 처리의 세 가지 원칙을 설명하기 위해이 기사는 예금 및 인출 및 청구서 발행과 같은 은행 계정 활동을 기록하고 추적하는 데 사용되는 개인 재무 관리자 Jcheckbook을 제작하여이를 논의합니다.
콘크리트와 명확한
Java는 Throwable부터 시작하고 오류 및 예외를 확장하며 Exception은 Runtimeexception을 확장하는 예외 클래스의 계층 구조를 정의합니다. 그림 1과 같이.
이 네 가지 클래스는 일반화되며 많은 오류 정보를 제공하지 않습니다. 이러한 클래스를 인스턴스화하는 것은 구문 적으로 합법적이지만 (예 : New Throwable ()),이를 가상 기본 클래스로 취급하고보다 전문화 된 하위 클래스를 사용하는 것이 가장 좋습니다. Java는 많은 예외 서브 클래스를 제공했습니다. 보다 구체적으로 원한다면 자신의 예외 클래스를 정의 할 수도 있습니다.
예를 들어 : Java.io 패키지는 FilenotFoundException, eofexception 및 ObjectStreamException과 같은 IOException의보다 전문적이고 서브 클래스 인 Exception Class IOException의 서브 클래스를 정의합니다. 각각은 특정 클래스의 I/O 오류를 설명합니다 : 파일 손실, 예외 파일 종료 및 오류 직렬화 된 개체 스트림. 예외가 더 구체적 일수록 우리의 프로그램은 "무엇이 잘못되었는지"라는 질문에 대답 할 수 있습니다.
예외를 포착 할 때 가능한 한 명확 해지려고 노력하는 것도 중요합니다. 예를 들어 : Jcheckbook은 사용자의 파일 이름을 다시 제정하여 FilenotFoundException을 처리 할 수 있습니다. Eofexception의 경우 예외가 발생하기 전에 읽은 정보를 기반으로 계속 실행할 수 있습니다. ObjectStreamException이 발생하면 프로그램은 파일이 손상되었고 백업 파일 또는 기타 파일을 사용해야한다는 메시지를 표시해야합니다.
Java는 동일한 시도 블록에 대해 여러 캐치 블록을 정의 할 수 있으므로 각 예외를 별도로 적절하게 처리 할 수 있기 때문에 명시 적으로 예외를 쉽게 잡을 수 있습니다.
파일 prefsfile = 새 파일 (prefsfilename); {readpreferences (prefsfile);} catch (filenotfoundException e) {// 지정된 파일이 존재하지 않는다는 사용자에게 알림} catch (eofexception e) {// 파일의 끝에 도달했음을 사용자에게 경고 {// intrest} { / alert}} { / / alert} 다른 I/O // 오류가 발생한 사용자}JCheckBook은 여러 캐치 블록을 사용하여 예외 캡처에 대한 명시적인 정보를 사용자에게 제공합니다. 예를 들어 : FilEnotFoundException이 잡히면 사용자에게 다른 파일을 지정하라는 메시지가 표시 될 수 있습니다. 경우에 따라 여러 캐치 블록으로 가져온 추가 인코딩 노력은 필수 부담 일 수 있지만이 예에서는 추가 코드가 프로그램이보다 사용자 친화적 인 응답을 제공하는 데 도움이됩니다.
처음 3 개의 캐치 블록으로 처리 된 예외 외에도 마지막 캐치 블록은 IOException이 발생할 때보다 일반화 된 오류 정보를 사용자에게 제공합니다. 이런 식 으로이 프로그램은 가능한 한 많은 정보를 제공 할 수 있지만 다른 예상치 못한 예외를 처리 할 수 있습니다.
때때로 개발자는 정규화 된 예외를 포착하고 "특이성"에 대한 예외 클래스 이름 또는 인쇄 스택 정보를 표시합니다. 이것을하지 마십시오! 사용자는 도움을받지 않고 java.io.EOFException 또는 스택 정보를 볼 때만 두통이 있습니다. 구체적인 예외를 캡처해야하며 사용자에게 "인간 단어"로 프롬프트해야합니다. 그러나 예외 스택은 로그 파일에 인쇄 할 수 있습니다. 예외와 스택 정보는 사용자보다 개발자를 돕는 데 사용됩니다.
마지막으로 Jcheckbook은 readPreferences() 에서 예외를 포착하지 않지만 사용자 인터페이스 계층에 캐치와 처리 예외를 남겨 두어 대화 상자 또는 기타 방법을 사용하여 사용자에게 알릴 수 있습니다. 이것을 "지연 캡처"라고하며 아래에서 설명합니다.
일찍 버려
예외 스택 정보는 예외가 발생하는 장면을 정확하게 찾기 위해 클래스 이름, 메소드 이름, 코드 파일 이름 및 각 메소드 호출의 줄 번호를 포함하여 예외가 발생하는 메소드 호출 체인의 정확한 순서를 제공합니다.
java.lang.nullpointerexceptionat java.io.fileInputStream.open (java.io.fileInputStream.fileInputStream. <init> (fileInputStream.java:103)의 jcheckbook.readpreferences (jcheckbook.java:225) at jcheckbook.jcheckbook.startup (jcheckbook.java:116) at jcheckbook.jcheckbook. <init> (jcheckbook.java:27) at jcheckbook.jcheckbook.main (jcheckbook.java:318)
위의 내용은 FileInputStream 클래스의 Open () 메소드가 NullPointerException을 던지는 경우를 보여줍니다. 그러나 FileInputStream.close() 는 표준 Java 클래스 라이브러리의 일부이며,이 예외의 문제는 우리 코드 자체가 Java API가 아닐 가능성이 높습니다. 따라서 문제는 이전 방법 중 하나에 나타날 가능성이 높으며 다행히도 스택 정보에도 인쇄됩니다.
불행히도, NullPointerException은 Java에서 가장 유익한 (가장 일반적이고 충돌하는) 예외입니다. 우리가 가장 관심있는 내용은 전혀 언급되지 않습니다. 그래서 우리는 몇 걸음 물러서서 무언가 잘못된 곳을 찾아야했습니다.
추적 스택 정보를 뒤로 물러서 코드를 확인하면 오류의 원인이 빈 파일 이름 매개 변수가 readPreferences() 로 전달되었는지 확인할 수 있습니다. readPreferences() 는 빈 파일 이름을 처리 할 수 없다는 것을 알고 있으므로 즉시 조건을 확인하십시오.
public void readpreferences (String filename)는 불법적 인 {if (filename == null) {throw new new OregalArgumentException ( "filename is null"); } // if //.. //... 기본 설정 파일 읽기 ...} 예외를 조기에 던지면 ( "실패 빠르게"라고도 함) 예외는 명확하고 정확합니다. 스택 정보는 잘못된 내용 (불법 매개 변수 값이 제공 됨), 잘못된 이유 (파일 이름이 null이 될 수 없음) 및 잘못된 위치 ( readPreferences() 의 첫 부분)을 즉시 반영합니다. 이런 식으로 스택 정보는 진실로 제공 될 수 있습니다.
java.lang.ilegalargumentexception : filename은 jcheckbook.jcheckbook.startup (jcheckbook.jcheckbook.startup (jcheckbook.java:116)의 <checkbook.jcheckbook. (jcheckbook.java:27) at jcheckbook.jcheckbook.main (jcheckbook.java:318)
또한, IT에 포함 된 예외 정보 ( "파일 이름은 빈")는 비어있는 것이 무엇인지에 대한 질문에 명시 적으로 답변하여 예외를 더 풍부하게 만듭니다.
오류가 감지 될 때 즉시 예외를 던지면 실패가 달성됩니다. 불필요한 객체 구성 또는 파일 또는 네트워크 연결과 같은 리소스 사용량은 효과적으로 피할 수 있습니다. 마찬가지로, 이러한 자원을 개방하여 가져온 청소 작업은 저장 될 수 있습니다.
지연된 캡처
초보자와 마스터가 할 수있는 실수 중 하나는 예외를 처리 할 수있는 능력을 갖기 전에 프로그램을 잡는 것입니다. Java 컴파일러는 점검 된 예외를 잡거나 던져야하도록 요구함으로써 간접적 으로이 동작을 용이하게합니다. 자연스러운 방법은 시도 블록으로 즉시 코드를 랩핑하고 Catch를 사용하여 컴파일러의 오류를 피하기 위해 예외를 포착하는 것입니다.
문제는 잡힌 후 예외를 얻으면 어떻게해야합니까? 최악의 일은 아무것도하지 않습니다. 빈 캐치 블록은 전체 예외를 블랙홀에 던지는 것과 같습니다. 오류가 언제, 왜 잘못되었는지 설명 할 수있는 모든 정보는 영원히 손실 될 것입니다. 로그에 예외를 작성하는 것이 조금 낫습니다. 적어도 확인할 레코드가 있습니다. 그러나 사용자가 로그 파일 및 예외 정보를 읽거나 이해할 것으로 기대할 수는 없습니다. jcheckbook은 현재 데스크톱 응용 프로그램이지만 HTML 기반 웹 응용 프로그램으로 전환 할 계획이므로 readPreferences() 오류 메시지 대화 상자를 표시하는 것도 적절하지 않습니다. 이 경우 오류 대화 상자를 표시하는 것은 분명히 옵션이 아닙니다. 동시에 HTML 또는 C/S 버전에 관계없이 구성 정보는 서버에서 읽히고 오류 메시지를 웹 브라우저 또는 클라이언트 프로그램에 표시해야합니다. readPreferences() 설계시 이러한 미래의 요구를 고려해야합니다. 사용자 인터페이스 코드와 프로그램 로직을 적절히 분리하면 코드의 재사용 성이 향상 될 수 있습니다.
조건부 처리 전에 예외를 조기에 포착하면 종종 더 심각한 오류 및 기타 예외가 발생합니다. 예를 들어, 위의 readPreferences() 메소드가 FileInputStream 생성자가 호출 될 때 발생할 수있는 filenotFoundException을 즉시 캡처하고 기록하면 코드가 다음과 같습니다.
public void readpreferences (String filename) {// ... inputStream in = null; //이 작업을 수행하지 마십시오 !!! 시도 {in = new FileInputStream (filename);} catch (filenotfoundException e) {logger.log (e);} in.read (...); // ...}위의 코드는 filenotfoundException에서 복구 할 수있는 능력없이이를 캡처합니다. 파일을 찾을 수없는 경우 다음 방법은 분명히 읽을 수 없습니다. readpreferences ()가 존재하지 않는 파일을 읽도록 요청되면 어떻게됩니까? 물론 FilenotFoundException이 기록 될 것이며, 당시 로그 파일을 보면 알 수 있습니다. 그러나 프로그램이 파일에서 데이터를 읽으려고 할 때 어떻게됩니까? 파일이 존재하지 않기 때문에 변수가 비어 있고 NullPointerException이 발생합니다.
프로그램을 디버깅 할 때 Instinct는 로그 끝의 정보를 살펴 보라고 알려줍니다. 그것은 nullpointerexception 일 것이며, 매우 성가신 것은이 예외가 매우 특이하지 않다는 것입니다. 오류 메시지는 우리에게 무엇이 잘못되었는지 오도 할뿐만 아니라 (실제 오류는 nullPointerException 대신 filenotFoundException입니다) 오류의 출처를 오도합니다. 실제 문제는 NullPointerException이 발생한 행의 수를 벗어나서 여러 방법 호출과 클래스 파괴가있을 수 있습니다. 우리가 문제의 원인을 찾기 위해 통나무를 되돌아 볼 때까지 작은 물고기의 실제 실수에서 우리의 관심을 끌었습니다.
readPreferences() 실제로해야 할 일은 이러한 예외를 포착하지 않기 때문에 무엇이되어야합니까? 그것은 약간 반 직관적 인 것처럼 보이며, 가장 적절한 방법은 아무것도하지 않고 즉시 예외를 포착하지 않는 것입니다. readPreferences() 의 발신자에게 책임을 남기고 누락 된 구성 파일을 다루는 적절한 방법을 연구하게하십시오. 사용자에게 다른 파일을 지정하거나 기본값을 사용하라는 메시지가 표시 될 수 있습니다. 실제로 작동하지 않으면 사용자에게 경고하고 프로그램을 종료 할 수 있습니다.
통화 체인의 상류에서 예외를 처리하는 책임을 전달하는 방법은 메소드의 Throws 절에서 예외를 선언하는 것입니다. 가능한 예외를 선언 할 때 조심하면 더 구체적 일수록 더 좋습니다. 이는 방법을 호출하는 프로그램이 알고 처리 할 준비가되어야하는 예외 유형을 식별하는 데 사용됩니다. 예를 들어, readPreferences() 의 "지연 캡처"버전은 다음과 같습니다.
공개 void readpreferences (String filename)는 불법 행위 exception, filenotfoundException, ioException {if (filename == null) {throw new 불법 불법 행위 렉싱 ( "Filename is null"); } // if // ... inputStream in = new FileInputStream (filename); // ...}기술적으로, 우리가 선언 해야하는 유일한 예외는 ioexception이지만, 우리는이 방법이 filenotfoundException을 던질 수 있다고 명시 적으로 선언합니다. 불법 행위 예외는 점검되지 않은 예외 (즉, runtimeexception의 서브 클래스)이기 때문에 선언 할 필요가 없습니다. 그러나 우리 코드를 문서화하도록 선언됩니다 (이러한 예외는 방법의 Javadocs에도 표시되어야합니다).
물론, 결국 귀하의 프로그램은 예외를 포착해야합니다. 그렇지 않으면 예기치 않게 종료됩니다. 그러나 여기서의 속임수는 프로그램이 예외에서 의미있게 회복되고 더 깊은 오류를 일으키지 않고 계속 진행할 수 있도록 올바른 수준에서 예외를 포착하는 것입니다. 또는 사용자에게 오류를 복구하도록 안내하는 것을 포함하여 명확한 정보를 사용자에게 제공 할 수 있습니다. 방법이 유능하지 않은 경우 예외를 처리하지 말고 뒤에 남겨두고 올바른 수준에서 처리하십시오.
요약
숙련 된 개발자는 디버깅 프로그램의 가장 큰 어려움은 결함을 고치는 것이 아니라 막대한 양의 코드에서 결함의 은신처를 찾는 것임을 알고 있습니다. 이 기사의 세 가지 원칙을 따르는 한, 예외는 결함을 추적하고 제거하고 프로그램을보다 강력하고 사용자 친화적으로 만드는 데 도움이 될 수 있습니다. 위의 내용은이 기사의 전체 내용이며 연구 나 작업에 도움이되기를 바랍니다.