Exception (예외) 의 개념과 사용 이유
Exception 은 '예외'라는 뜻이다. Exception에 대해 정리하기 전에 궁금증이 생겼습니다.
예외와 오류의 차이는 뭐지?
위의 물음을 해결하고자 예외와 오류의 차이를 먼저 정리하고 가겠습니다.
0. Exception (예외) 와 Error (오류)의 차이
Java Documatation 을 확인해 봐도 Exception과 Error는 다르다고 가지 치기를 해놓은걸 확인할 수 있습니다.
결론부터 말하자면, 예외와 오류의 가장 큰 차이는 발생후 처리 가능성입니다.
그 말인 즉슨, 예외의 경우 프로그램적으로 처리가 가능하기 때문에 일반 개발자가 핸들링이 가능하고, 오류의 경우는 프로그램 자체가 종료될 수 있다는 점과 개발자가 핸들링할 수 없다는 특징이 있습니다. 그럼 좀 더 나아가 예외의 종류에 대해 짚고 넘어 가겠습니다.
1. 예외의 종류
예외의 종류는 아래의 표와 같이 정리 할 수 있습니다.
예외 구분 | 설명 | 종류 |
일반적인 예외(Checked Exception) | 1. 컴파일시에 발생하는 예외 2. 반드시 예외처리를 해야하는 경우 |
1. FileNotFoundException 2. InterruptedException |
실행시 예외(Unchecked Exception) | 1. 프로그램이 실행되다가 발생하는 예외 2. 예외 처리를 하지 않아도 컴파일상 문제가 없는 경우 |
1. ArrayIndexOutBoundsException ArithmeticException |
즉, 둘의 차이를 한줄로 정리하면, 컴파일 전/후에 알 수 있는가이다. 그럼 이제 예외의 경우에는 개발자가 핸들링이 가능하다고 했기 때문에 핸들링하는 방법에 대해 정리하겠습니다.
2. 예외 처리 방법
try {
// 예외가 발생할 여지가 있는 소스코드위치
} catch (Exception ex) {
// 예외가 발생시 처리내역
} finally {
// try-catch 절이 끝난 뒤 마지막으로 처리할 내역
}
자바에서 사용하는 예외 처리를 위한 소스 코드의 기본 문법입니다.
- try : 예외가 발생할 여지가 있는 로직을 작성 부분
- catch : 예외 발생시 처리할 로직을 작성하는 부분
- finally : 예외 발생 유무와 상관없이 무조건 실행할 로직을 작성하는 부분
3. 예외처리는 왜 하는가?
회원가입을 위한 비즈니스 로직을 예로 들어 보겠습니다. 회원 가입을 하기 위해서 개발자는 아래에서 정의한 5개의 로직을 수행하는 프로그램을 작성해야 합니다.
- 아이디 중복 검증을 해야한다.
- 이메일 검증을 해야 한다.
- 패스워드가 설정한 기준에 부합하는 검증 해야 한다.
- 휴대폰 검증을 해야 한다.
- 데이터베이스에 회원정보를 저장한다.
만약 아래의 로직을 작성하기 위해 try catch문을 사용하지 않고 조건문을 사용한다고 가정하면 아래의 코드처럼 작성 할 것입니다.
if 아이디 중복체크 검증을 통과 했는가 {
if 이메일 검증을 통과 했는가 {
if 비밀번호 검증을 통과 했는가 {
if 휴대폰 검증을 통과 했는가 {
데이터베이스에 회원정보를 저장한다.
}
else {
휴대폰 검증을 통과 하지 못했을 때
}
}
else {
비밀번호 검증을 통과 하지 못했을 때
}
}
else {
이메일 검증을 통과 하지 못했을 때
}
}
else {
아이디 중복체크 검증을 통과 하지 못했을 때
}
위의 코드는 한눈에 보기도 힘들뿐더러, 지금은 회원가입을 위한 비즈니스 로직이 저것보다 더 많아진다고 하면 해당 프로그램의 소스코드를 유지보수 하는 측면에서 비효율적인 코드일 것입니다. 때문에 예외처리를 사용해야 하는 것입니다.
try {
아이디 검증
이메일 검증
비밀번호 검증
전화번호 검증
} catch (아이디 검증이 실패 했을 때) {
} catch (이메일 검증이 실패 했을 때) {
} catch (비밀번호 검증이 실패 했을 때) {
} catch (전화번호 검증이 실패 했을 때) {
}
finally {
예외처리와 관계없이 수행할 로직
}
try catch문으로 예외처리를 한 경우입니다. 한눈에 봐도 예외 발생 시마다 어떤 로직을 처리하는지 한눈에 보기 쉽게 되어있습니다.
다만, try catch문을 작성할 때는 한 가지 문법적 주의사항은 예외의 상위 클래스는 하위 클래스보다 catch문이 위에 있을 수 없다는 것입니다. 아래의 코드에서 'ArrayIndexOutBoundsException'는 'Exception'을 상속받는 하위 클래스로 catch문을 작성할 때는 상위 클래스가 먼저 작성될 수 없다는 것만 주의하면 될 것 같습니다.
catch(ArrayIndexOutBoundsException ex) {
}
catch(Exception ex) {
}
try catch문을 무분별하게 사용하면 오히려 OOP 적 관점을 해칠 수 있습니다. 코드의 재사용은 매우 OOP적 관점에서 중요한 개념이기 때문입니다. 예를 들어 다른 유형의 비즈니스 로직이 추가된다고 가정해 봅시다. 그럼 조건문을 여러 개 사용했던 것처럼 try catch 문도 여러 개를 사용해야 하는 경우가 발생합니다. 이러한 상황을 지양하고자 등장한 개념이 throw와 throws입니다.
4. throw와 throws
public static void main(String [] args ) {
try {
아이디 검증
아이디 검증 예외시 호출 되는 메서드();
이메일 검증
비밀번호 검증
전화번호 검증
} catch (아이디 검증이 실패 했을 때) {
} catch (이메일 검증이 실패 했을 때) {
} catch (비밀번호 검증이 실패 했을 때) {
} catch (전화번호 검증이 실패 했을 때) {
}
finally {
예외처리와 관계없이 수행할 로직
}
}
public static void 아이디 검증 예외시 호출 되는 메서드 throws 아이디 검증이 실패 했을 때 {
throw new Exception(); // 강제 예외 발생
}
이런 식으로 사용되는데 구체적으로 하나 하나 뜯어서 설명해보겠습니다. 먼저 'throws'는 예외를 처리한다기보다는 발생한 예외 객체를 양도하는 것입니다.
여기서는 아이디 검증 시 예외가 발생했고 '아이디 검증 예외시 호출되는 메서드' 호출해 아이디 검증이 실패했을 때 Exception 객체를 생성해 호출했던 위치로 전달하고 그 객체를 통해 catch문을 작성하는 것입니다.
정리하자면
1. 예외와 오류는 다르다.
2. 예외의 종류에는 일반적 예외와 실행 시 예외가 있다.
3. 예외 처리를 하기 위해서 try catch문을 사용한다.
4. OOP를 지향한 예외 처리를 위한 코드를 사용해야만 한다.