티스토리 뷰

웹/Spring

스프링 볶음밥 - 4장 - 예외

세댕댕이 2022. 7. 4. 15:11

 

 

 

[이전 글]

더보기

볶음밥 1장 - 1,2,3: 자바빈, 디자인 패턴(템플릿 메소드, 팩토리 메소드, 전략 패턴), 관심사의 분리, SOLID 및 객체지향 약간

볶음밥 1장 - 4,5,6: 제어의 역전, 프레임워크 vs 라이브러리, 스프링 IoC 및 용어 정리, 싱글톤, 동일성 vs 동등성, 빈의 스코프

볶음밥 1장 - 7: 의존관계 주입(DI), DL, IoC

볶음밥 2장: 테스트, TDD, jUnit

볶음밥 3장: 템플릿/콜백

 

 

[4장] 예외

 

1. 예외를 무시하거나 잡아먹어 버리는 코드를 만들지 마라

모든 예외는 적절하게 복구되든지 / 작업을 중단시키고 개발자에게 명확하게 통보되든지 해야한다

- 예외가 발생했다는 것은 어디선가 심각한 문제가 발생했다는 것 

-> 예외를 무시하고 정상인것처럼 그냥 다음 코드로 넘어가는 것은 심각한 문제를 일으킬수 있다.

(그냥 아무것도 안하거나 로그만 띡 찍어놓는것 등..) = try/catch로 잡는게 전부가 아니다

 

 

2. throws Exception으로 퉁치지 마라

Exception 이름이 길고 귀찮다고 그냥 모든 메소드에 최상위 예외인 throws Exception 박아넣기 하지 마라

- 메소드 선언에서 의미있는 정보를 얻을 수 없다

 

 

(뜨끔한다...)

 

 

[예외의 종류와 특징]

1. Error

- java.lang.Error 클래스의 서브클래스

- 시스템에 뭔가 비정상적인 상황이 발생했을 때 사용.

- 시스템 레벨, 자바 VM 단에서 던지는 에러.

- 애플리케이션 코드에서는 대응할 수 없음

- OutOfMemoryError, ThreadDeath 등.

 

2. Exception

- java.lang.Exception 클래스의 서브 클래스

 

2-1. Checked Exception

- 일반적으로 예외라고 하면 얘를 뜻한다고 보면 된다

- 이를 사용하려면 예외를 처리하는 코드를 반드시 함께 작성해야 한다. (컴파일 단계에서 확인한다)

-- catch문으로 잡아서 처리하든가, 다시 throws를 정의해서 밖으로 던져야 한다.

- ClassNotFoundException, FileNotFoundException, IOException 등..

 

2-2. Unchecked Exception (=런타임 예외)

- Runtime Exception을 상속한 클래스

- 굳이 catch / throws를 안해도 된다 (명시적으로 해줘도 된다)

- (개발자의 부주의에 의한) 프로그램에 오류가 있을 때 발생하도록 의도된 것들.

- NullPointerException, ArrayIndexOutOfBoundsException 등..

 

 

[예외 처리 방법]

1. 예외 복구: 예외 상황을 파악하고 문제를 해결해서 정상으로 돌려놓자

 

2. 예외처리 회피: 예외를 처리하지 않고 자신을 호출한 쪽으로 던져버리자 (rethrow, 짬때리기...)

- 예외를 회피하는 것은 명확한 의도가 있어야 한다. 그렇지 않으면 무한 throws Exception을 유발할 수 있다.

-- 자신을 사용하는 쪽에서 예외를 처리하는 것이 최선이라는 확신이 있을 때에만 짬때리는 것이 좋다.

 

3. 예외 전환(Exception Translation): 예외 회피와 같이 예외를 메소드 밖으로 던지는 것이나, 발생한 예외를 그대로 던지는 것이 아니고 적절한 예외로 변환해서 던지는 것이다. (커스텀 예외로 변환 등..)

 

Case 1) 내부에서 발생한 예외가 예외상황에 대한 적절한 의미를 부여해주지 못하는 경우 

 

Case 2) 예외처리를 쉽고 단순하게 만들기 위해서 포장(Wrap) 하고자 하는 경우

--> 예외처리를 강제하는 체크 예외를 언체크 예외로 전환하고자 할 때 등..

 

* 예외 전환을 할 경우에는 기존 예외 + 전환 예외를 담아 중첩 예외(Nested Exception)으로 만들어 주는 것이 좋다.

try {
    ...
} catch (SQLException e) {
    // 커스텀 예외로 전환
    throw new DuplicateUserIdException().initCause(e);
}

- initCause() 메소드로 기존 예외를 같이 담아 넘겨주면 된다

 

* 체크 예외를 계속 throws 를 이용해 떠넘기기만 하는 것은 메소드만 지저분해지고 나쁜 습관이다!!

- 어차피 복구 불가능한 예외라면 런타임 예외로 포장해서 불필요한 throws 만들게 하지 말자

=> 런타임 예외 중심 전략!!

==> 복구할 수 있는 예외는 없다고 생각하고 예외가 생겨도 런타임 예외이므로 시스템 레벨에서 알아서 처리하거나, 꼭 필요하다면 직접 잡아서 대응하는 낙관적인 전략 (일단 반드시 잡고 보는 체크 예외와 대비된다)

 

* 그럼 체크 예외는 쓸 일이 없나? 

- 애플리케이션 자체 로직에 의해 의도적으로 발생시키고, 반드시 catch 해서 조치를 취하도록 요구하는 예외인 경우 (이를 "애플리케이션 예외"라고도 함)에는 의도적으로 체크 예외를 사용해야 한다.

- 반드시 대응해야할 예외 상황에 대한 로직 구현을 강제시킬 때 사용

 

 

[스프링의 역할]

- 스프링은 Jdbc 사용 시 발생하는 SQLException(체크 예외)DataAccessException(런타임 예외) 로 포장해주는 역할을 수행한다

- 애플리케이션 레벨에서 체크 예외에 대해 신경쓰지 않아도 되도록 해준다.

- 또한 SQLException보다 더 상세하면서도 일관성 있는 예외로 추상화 해준다.

(DataAccessException을 상속하는 BadSqlGrammerEx, DuplicatedKeyEx 등...)

- DB에 독립적인 유연한 코드를 작성할 수 있도록 돕는다

-- Oracle, MySQL 등마다 사용하는 SQL 문장, 던지는 예외의 이름 등이 각기 다르다. 스프링은 이렇게 DB 벤더마다 각기 다른 예외를 매핑 테이블을 이용해 DataAccessException 상속 예외로 변환해준다

--> 기술에 독립적인 개발을 가능하게 해준다!!!!

(인터페이스 도입 + 런타임 예외 전환 + 기술에 독립적인 추상적인 예외 사용)

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함