본문 바로가기

Language/Java

Exception (예외) 의 개념과 사용 이유

Exception 은 '예외'라는 뜻이다. Exception에 대해 정리하기 전에 궁금증이 생겼습니다.

예외와 오류의 차이는 뭐지?

 

위의 물음을 해결하고자 예외와 오류의 차이를 먼저 정리하고 가겠습니다. 


0. Exception (예외) 와 Error (오류)의 차이

 

https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Exception.html

 

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개의 로직을 수행하는 프로그램을 작성해야 합니다. 

  1. 아이디 중복 검증을 해야한다.
  2. 이메일 검증을 해야 한다.
  3. 패스워드가 설정한 기준에 부합하는 검증 해야 한다.
  4. 휴대폰 검증을 해야 한다.
  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를 지향한 예외 처리를 위한 코드를 사용해야만 한다.

반응형