이 기사는 Java 예외를 선택하고 사용하는 데있어 몇 가지 오해에 중점을 둡니다. 독자들이 예외 처리의 일부 요점과 원칙을 마스터하고 요약 및 유도에주의를 기울일 수 있기를 바랍니다. 예외를 처리하면 개발자의 기본 품질을 향상시키고 시스템의 견고성을 향상 시키며 사용자 경험을 향상 시키며 제품의 가치를 향상시킬 수 있습니다.
오해 1. 비정상적인 선택
그림 1. 이상 분류
그림 1은 예외의 구조를 설명합니다. 실제로, 우리는 이상이 이상과 비정상적인 이상을 감지하는 것으로 나뉘어져 있음을 알고 있지만 실제로는이 두 가지 이상의 적용이 혼란스러워집니다. 검출되지 않은 예외는 사용하기 쉽기 때문에 많은 개발자들은 예외의 탐지가 쓸모가 없다고 생각합니다. 실제로 비정상적인 응용 시나리오는 다음과 같이 요약 할 수 있습니다.
1. 통화 코드는 계속 실행될 수 없으며 즉시 종료해야합니다. 서버가 연결되어 있지 않고 매개 변수가 올바르지 않은 것과 같은이 상황에 대한 가능성이 너무 많습니다.이 시점에는 감지되지 않은 예외가 적용 가능하며 코드의 명시 적 캡처 및 처리를 호출 할 필요가 없으며 코드는 간결하고 명확합니다.
2. 호출 코드는 추가 처리 및 복구가 필요합니다. sqlexception이 검출되지 않은 예외로 정의되면, 개발자는 자연스럽게 sqlexception이 코드의 명시 적 캡처 및 처리를 호출 할 필요가 없다고 생각하며, 이는 연결을 닫지 않고 트랜잭션을 롤백하지 않고 DB의 더러운 데이터로 이어질 것입니다. Sqlexception은 코드가 예외를 생성 한 후 개발자가 자원을 명시 적으로 캡처하고 정리할 수 있도록 예외를 감지하는 것으로 정의되기 때문입니다. 물론, 자원을 정리 한 후에는 프로그램의 실행을 방지하기 위해 검출되지 않은 예외를 계속 던질 수 있습니다. 관찰 및 이해에 따르면, 예외의 탐지는 대부분 공구 클래스에 적용될 수 있습니다. Java Learning Group 669823128
오해 2 : 페이지 나 클라이언트에 직접 예외를 표시합니다.
클라이언트쪽에 직접 예외를 인쇄하는 것이 일반적입니다. 코드가 실행되면 JSP를 예로 들어 보면 컨테이너는 기본적으로 페이지에서 예외 스택 정보를 직접 인쇄합니다. 실제로 고객의 관점에서 볼 때 모든 예외는 실질적인 의미가 없으며 대부분의 고객은 예외 정보를 전혀 이해할 수 없습니다. 소프트웨어 개발은 또한 예외를 사용자에게 직접 제시하지 않도록 노력해야합니다.
목록 1
<strong> package </strong> com.ibm.dw.sample.exception;/*** Custom Runtimeexception* 오류 코드 속성 추가*/<strong> public </strong> <strong> class </strong> <strong> runtimeexception </strong> <strong> 확장 </strong> <strong> java </strong> <strong> </defular coter>. <strong> public </strong> <strong> 정적 </strong> <strong> Final </strong> integer generic = 10000000; // 오류 코드 <strong> private </strong> 정수 오류 코드; <strong> public </strong> <strong> runtimeexception </strong> (정수 오류 코드, 던질 가능한 원인) {<strong> this </strong> (ErrorCode, <strong> null </strong>, 원인); } <strong> public </strong> <strong> runtimeexception </strong> (문자열 메시지, 던질 가능한 원인) {// 일반 오류 코드 <strong> 사용 </strong> (일반, 메시지, 원인); } <strong> public </strong> <strong> runtimeexception </strong> (정수 오류 코드, 문자열 메시지, 던질 가능한 원인) {<strong> super </strong> (메시지, 원인); <strong> this </strong> .errorCode = ErrorCode; } <strong> public> public> 정수 <strong> geterRorCode </strong> () {<strong> return </strong> ErrorCode; }}예제 코드가 표시된 것처럼 예외에 오류 코드를 소개하십시오. 예외가 발생하면 예외의 오류 코드를 사용자에게 제시하거나 오류 코드를보다 이해할 수있는 프롬프트로 변환합니다. 실제로 여기의 오류 코드에는 다른 기능도 포함되어 있으며 개발자는 오류 코드를 기반으로 어떤 유형의 예외가 발생했는지 정확하게 알 수 있습니다.
오해 3 : 코드 계층 구조의 오염
우리는 종종 코드를 서비스, 비즈니스 로직, DAO 등과 같은 다른 계층으로 나눕니다. DAO 계층에는 목록 2에 표시된 것처럼 예외를 던지는 방법이 포함됩니다.
목록 2
<strong> public </strong> customer <strickecustomerbyid </strong> (long id) <strong> 던지기 </strong> sqlexception {// id id} query}언뜻보기에 위의 코드에는 아무런 문제가 없지만 설계 커플 링의 관점에서 신중하게 생각하면 Sqlexception은 상단 호출 코드를 오염시킵니다. 호출 레이어는 Try-Catch를 명시 적으로 사용하여 캡처하거나 더 높은 수준으로 던져야합니다. 디자인 격리 원칙에 따라, 우리는이를 다음과 같이 적절하게 수정할 수 있습니다.
목록 3
<strong> public </strong> customer <strickecustomerByid </strong> (long id) {<strong> try </strong> {// id} <strong> catch </strong> (sqlexception e) {// 비 기원 예외 예외를 예외를 감지하기 위해 <strong> <strong> <strong> <strong> <strong> <strong>를 감지합니다. runtimeexception (sqlerrorcode, e); } <strong> 마지막으로 </strong> {// 연결을 닫고 리소스 정리}}}오해 4 : 예외를 무시하십시오
다음과 같은 예외 처리는 콘솔에 예외를 출력하는 것입니다. 또한 여기에는 예외가 나타나고 프로그램이 중단되지 않으며 통화 코드가 계속 실행되어 더 많은 예외가 생깁니다.
목록 4
<strong> public </strong> <strong> void </strong> <strong> restrieveObjectByid </strong> (Long id) {<strong> try </strong> {/.................... * 생산 환경에서 오류 스택은 로그에 출력해야합니다. * 캐치 프로세스 후에 프로그램이 계속 실행되며, 이는 추가 문제로 이어질 것입니다*/ ex.printstacktrace (); }}재구성 할 수 있습니다.
목록 5
<strong> public </strong> <strong> void </strong> <strong> restrieveObjectByid </strong> (long id) {<strong> try </strong> {//.......................... 전); } <strong> 마지막으로 </strong> {// resultset, 문, 연결 등을 정리하십시오}}이 오해는 비교적 기본적이며 정상적인 상황에서는이 낮은 수준의 실수를하지 않을 것입니다.
오해 5 : 루프 명령문 블록에 예외를 포함시킵니다
다음 코드에 표시된 바와 같이, 예외는 for loop 문 블록에 포함되어 있습니다.
목록 6
</strong> (<strong> </strong> (<strong> int </strong> i = 0; i <100; i ++) {<strong> try </strong> {} <strong> catch </strong> (xxxexception e) {//…. }}우리는 모두 예외 처리가 시스템 리소스를 점유한다는 것을 알고 있습니다. 언뜻보기에 모든 사람은 그런 실수를하지 않을 것이라고 생각했습니다. 다른 관점에서, 루프는 클래스 A에서 실행되며 클래스 B의 방법은 루프에서 호출되지만 클래스 B에서 호출 된 방법에는 try-catch와 같은 명령문 블록이 포함되어 있습니다. 클래스의 계층 구조는 사라졌으며 코드는 위와 정확히 동일합니다.
오해 6 : 예외를 사용하여 모든 잠재적 예외를 캡처합니다
방법을 실행하는 동안 여러 가지 유형의 예외가 발생합니다. 코드의 단순성을 위해, 기본 클래스 예외는 다음 예에서 볼 수 있듯이 모든 잠재적 예외를 포착하는 데 사용됩니다.
목록 7
<strong> public </strong> <strong> void </strong> <strong> restrieveObjectByid </strong> (long id) {<strong> try </strong> {//… 코드 호출은 ioexception //… 코드 호출을 던지는 코드 호출}} <strong> catch </strong> (예외 e) {// 여기에 기본 클래스 예외가 잡혔습니다. 여러 레벨이이를 포착하면 원래 예외의 유효한 정보는 <strong> Throw </strong> <strong> new </strong> runtimeexception ( "Exception <strong> in </strown> retieveObjectById", e); }}재구성 될 수 있습니다
목록 8
<strong> public </strong> <strong> void </strong> <strong> restrieveObjectByid </strong> (long id) {<strong> try </strong> {//................ runtimeexception (/*여기에 ioexception에 해당하는 오류 코드를 지정하십시오*/코드, "예외 <strong> in </strong> retrieveObjectByid", e); } <strong> catch </strong> (sqlexception e) {// sqlexception <strong> 던지기 </strong> <strong> new </strong> runtimeexception (/*여기서 sqlexception에 해당하는 오류 코드를 지정하십시오*/코드, </strong> in </strong> repieveBjectById ", e); }}오해 7 : 다단계 캡슐화는 검출되지 않은 예외를 던집니다
우리가 항상 다른 유형의 예외가 다른 캡처 문을 사용해야한다고 주장한다면, 대부분의 예는이 섹션을 우회 할 수 있습니다. 그러나 하나의 코드 호출 만 하나 이상의 예외를 던지면 각각의 다른 유형의 예외에 대해 Catch 문을 작성할 필요가 없습니다. 개발의 경우 모든 예외만으로도 프로그램의 특정 문제를 설명하기에 충분합니다.
목록 9
<strong> try </strong> {// runtimeexception, ioexeption 또는 다른 사람이 던질 수 있습니다. // 여기와 오해 6의 차이점에 주목하십시오. 여기에 여러 예외를 던지는 코드가 있습니다. 위는 여러 가지 코드 세그먼트이며, 각각 다른 예외를 던지는} <strong> catch> (<strong> Exception </strong> e) {// 항상 runtimeexception으로 예외를 변환하지만 실제로는 runtimeexception의 인스턴스이며 이전 코드에서 캡슐화되었습니다. runtimeexception (/**/code,/**/, e);}위의 예와 같이 모든 예외를 runtimeexception으로 변환하면 예외 유형이 이미 runtimeexception이면 다른 캡슐화를 수행합니다. runtimeexception이 다시 캡슐화되었고, 원래 runtimeexception에 의해 수행되는 유효한 정보가 손실되었습니다.
솔루션은 Runtimeexception 클래스에 관련 검사를 추가하여 매개 변수 Throwable이 runtimeexception의 인스턴스가 아니라는 것을 확인할 수 있다는 것입니다. 그렇다면 해당 속성을 새로 생성 된 인스턴스에 복사하십시오. 또는 다른 캐치 문 블록을 사용하여 runtimeexception 및 기타 예외를 포착하십시오. 개인 선호도 방법 1, 혜택은 자명합니다.
오해 8 : 다단계 인쇄 예외
먼저 2 개의 클래스 A와 B를 정의하는 다음 예를 살펴 보겠습니다. 클래스 B 코드는 클래스 A에서 호출되고 클래스 A 및 클래스 B 캡처 및 인쇄 예외가 모두 호출됩니다.
목록 10
<strong> public </strong> <strong> 클래스 </strong> <strong> a </strong> {<strong> private </strong> <strong> static </strong> logger = loggerfactory.getLogger (a.class); <strong> public </strong> <strong> void </strong> <strong> 프로세스 </strong> () {<strong> try </strong> {// 클래스 B를 인스턴스화하면 b b = <strong> new </strong> b ()와 같은 다른 주입 방법으로 변경할 수 있습니다. b.process (); // 다른 코드는 예외를 유발할 수 있습니다} <strong> catch </strong> (xxxexception e) {// 클래스 B 프로세스 메소드가 예외를 던지면 예외가 B에 인쇄되고 여기에 인쇄됩니다. <strong> 던지기 </strong> <strong> new </strong> runtimeexception (/*오류 코드*/errorcode,/*예외 정보*/msg, e); }}} <strong> public </strong> <strong> 클래스 </strong> <strong> b </strong> </strong> {<strong> private> private </strong> <strong> static </strong> logger = loggerfactory.getLogger (b.class); <strong> public </strong> <strong> void </strong> <strong> 프로세스 </strong> () {<strong> try </strong> {// 예외를 던질 수있는 코드} <strong> catch </strong> (xxxexception e) {logger.error (e); <strong> 던지기 </strong> <strong> new </strong> runtimeexception (/*오류 코드*/errorcode,/*예외 정보*/msg, e); }}}동일한 예외가 2 번 인쇄됩니다. 레벨이 조금 더 복잡하다면 인쇄 로그의 시스템 성능을 고려하지 않고 예외 로그에서 특정 문제를 찾는 것이 두통입니다.
실제로 인쇄 로그는 코드의 가장 바깥 쪽 레이어에서 캡처 및 인쇄 만 필요합니다. 예외 인쇄는 또한 AOP로 작성되어 프레임의 가장 바깥 쪽 층으로 직조 될 수 있습니다.
오해 9 : 예외에 포함 된 정보가 완전히 위치 할 수없는 문제
예외는 개발자가 무엇이 잘못되었는지 알 수있을뿐만 아니라 더 자주 개발자는 문제의 원인을 알아야합니다. Java .lang.xception에는 문자열 유형 매개 변수의 생성자가 있으며이 문자열은 이해하기 쉬운 신속한 정보로 사용자 정의 할 수 있습니다.
간단한 사용자 정의 정보 개발자는 예외가 나타나는 위치 만 알 수 있지만 많은 경우 개발자가 이러한 예외를 일으키는 매개 변수에 대해 더 알아야합니다. 현재 메소드 호출의 매개 변수 정보를 사용자 정의 정보에 추가해야합니다. 다음 예제는 하나의 매개 변수의 경우 만 나와 있습니다. 여러 매개 변수의 경우 이러한 문자열을 구성하기 위해 도구 클래스를 작성할 수 있습니다.
목록 11
public <strong> void> retrieve> regrieveObjectById (long id) {<strong> try </strong> {//.... smexception} <strong> catch </strong> (sqlexception ex) {// 예외 정보에 매개 변수 정보 추가 <strong> <strong> new </strong> runtimeexception ( "</strong> in </retieve> in </strong> in </strong> </strong> Object ID와 함께 <strong> : "+ id, ex); }}오해 10 : 잠재적 이상을 예측할 수 없습니다
코드를 작성하는 과정에서 호출 코드에 대한 깊은 이해가 부족하여 호출 코드가 예외를 생성할지 정확하게 결정할 수 없으므로 처리가 무시됩니다. 생산 버그가 생성 된 후, 나는 특정 코드에 예외 검색을 추가해야한다는 것을 기억했으며 예외의 원인을 정확하게 지적 할 수 없었습니다. 이를 위해서는 개발자가 자신이하는 일을 알고있을뿐만 아니라 다른 사람들이 수행 한 작업과 가능한 결과를 가능한 한 많이 알고 전체 응용 프로그램의 처리 프로세스를 글로벌 관점에서 고려해야합니다. 이러한 아이디어는 코드 작성 및 처리에 영향을 미칩니다.
오해 11 : 여러 타사 로그 라이브러리의 혼합 사용
요즘에는 점점 더 많은 Java 타사 로그 라이브러리가 있습니다. 다양한 프레임 워크가 대규모 프로젝트에 도입 될 것이며, 이러한 프레임 워크는 다양한 로그 라이브러리의 구현에 의존 할 것입니다. 가장 번거로운 문제는 필요한 모든 로그 라이브러리를 소개하는 것이 아니라, 문제는 소개 된 로그 라이브러리가 그 자체로 양립 할 수 없다는 것입니다. 프로젝트 초기 단계에서 쉽게 해결할 수있는 경우 필요에 따라 코드에 모든 로그 라이브러리를 다시 소개하거나 프레임 워크로 변경할 수 있습니다. 그러나 이러한 종류의 비용은 모든 프로젝트에 적합하지는 않으며 프로젝트가 진행됨에 따라 위험이 커집니다.
어떻게 비슷한 문제를 효과적으로 피할 수 있습니까? 대부분의 프레임 워크는 이제 비슷한 문제를 고려했습니다. LIB 라이브러리에서 속성 또는 XML 파일, 매개 변수 또는 런타임 스캔 로그 구현 클래스를 구성 할 수 있으며 응용 프로그램이 실행중인 경우에만 적용 할 특정 로그 라이브러리를 결정할 수 있습니다.
실제로, 여러 수준의 로그 인쇄를 요구하지 않는 원칙에 따라 원래 로그 인쇄 코드라고하는 많은 클래스를 단순화 할 수 있습니다. 대부분의 경우 인터셉터 또는 필터를 사용하여 로그를 인쇄하여 코드 유지 보수 및 마이그레이션 비용을 줄일 수 있습니다.
결론
위의 것은 순전히 개인적인 경험과 요약입니다. 상황은 변증 법적이며 절대적인 원칙은 없습니다. 가장 효과적인 원칙은 귀하에게 적합합니다. 위의 설명과 분석이 도움이되기를 바랍니다.