자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
1. try - catch-finally
자바에서 모든 예외는 Exception이라는 클래스를 상속 받는다. 해당 계층 구조는 아래 단락에서 소개하겠다.
예외 처리 방식은 아래와 같다.
try{
//예외가 발생될만한 코드
}catch(FileNotFoundException e){ //FileNotFoundException이 발생했다면
}catch(IOException e){ //IOException이 발생했다면
}catch(Exception e){ //Exception이 발생했다면
}finally{
///어떤 예외가 발생하던 말던 무조건 실행
}
try 블록 : 이 블록에서 예외가 발생할만한 코드가 쓰여진다.
catch (예외 종류) 블록 : 이 부분에서 예외가 발생되었을 때 처리하는 동작을 명시한다. catch블록은 다수가 존재할 수 있다. 맨 처음 catch 블록에서 잡히지 않는 예외라면 다음 catch의 예외를 검사한다. 이때 상속 관계에 있는 예외 중 부모가 위의 catch, 그리고 그 자식 예외 클래스가 아래의 catch로 놓일 순 없다.
try{
//.. 중략 ..//
} catch (Exception e){
//컴파일 오류 발생
} catch (IOException e){
}
Exception 클래스는 모든 예외의 부모클래스이기 때문에 Exception을 IOException 보다 위에서 처리할 수 없다는 의미이다. 이때 IOException이 아래에 위치하여 해당 catch 블록은 도달할 수 없는 블로깅 되기 때문이다.
finally 블록 : 해당 블록에서는 예외의 발생 여부와 상관없이 항상 수행되어야할 코드가 쓰여진다. 임시 파일의 삭제, 할당된 객체의 free 등이 이루어진다.
public static void main(String[] ar){
int a,b;
a=10;
b=0;
try {
int c=a/b;
System.out.println(c); //예외발생으로 실행 불가한 코드
}catch(ArithmeticException e) {
System.out.println("ArithmeticException 발생");
System.out.println("0으로 나눌 수는 없습니다");
e.printStackTrace(); // 어느 부분에서 예외가 발생하였는지 알려주는 추적 로그를 보여준다.
}finally {
System.out.println("finally 실행");
}
}
ArithmeticException 발생
java.lang.ArithmeticException: / by zero
at aa.Main.main(Main.java:11) //Main.java에서 11번째 줄에서 발생했다는 printStackTrace
finally 실행
2. throw, throws
throws를 이용하여 예외를 해당 구현 코드에서 처리하지 않고, 그 구현 코드를 호출해 사용하는 부분에서 예외 처리를 할 수 있다.
public static void divide(int a,int b) throws ArithmeticException {
if(b==0) throw new ArithmeticException("0으로 나눌 수는 없다니까?");
int c=a/b;
System.out.println(c);
}
public static void main(String[] ar){
int a=10;
int b=0;
divide(a,b);
}
divide() 메소드는 a와 b를 나눈 후에 출력하는 역할을 하는데, 이 나누기 부분에서 b가 0일 때, 예외가 발생할 수 있다.
이때, divide()를 호출한 곳에서 예외가 발생한 다음의 처리를 divide() 메소드가 정하지 않기 때문에 divide()를 호출하는 곳에서 예외를 처리하도록 한다.
이를 위해 divide() 메소드에 ArithmeticException을 추가하여 divde() 안에서 난 예외를 main에 던져줌으로 예외처리를 할 수 있다.
그리고 이 throws된 ArithmeticException과 같은 Exeption을 받은 main에서는 try-catch를 이용해 예외처리를 할 수 있다.
자바가 제공하는 예외 계층 구조
Exception과 Error의 차이는?
컴파일할 때 발생할 수 있는 컴파일 오류와 실행 중 발생되는 런타임 오류 두 종류가 있다. 컴파일 오류는 개발자가 발견하기 쉬우나, 런타임 오류는 그렇지 못하다. 이때, 자바에서는 런타임 오류를 Error와 Exception으로 분류한다.
int a,b;
a=10;
b=0;
int c=a/b;
System.out.println(c);
// 출력문
Exception in thread "main" java.lang.ArithmeticException: / by zero
at aa.Main.main(Main.java:11)
위와 같은 상황에서 개발자는 조건문을 통해 0으로 나누지 못하게 제한할 수 있다. 이처럼 예측가능한 상황에서 오류를 제어할 수 있는 것이 예외이다.
예외는 Compile 시에 발견할 수 잇는 예외와 프로그램 실행 시에 발생하는 예외 두 종류가 있다. Compile 시에 발생할 수 있는 예외는 일반적으로 IDE에서 빨간줄로 표시된다. 하지만 위 코드처럼 Compile 시에 발견하지 못하는 에러를 Runtime Error라 하는데 이때는 개발자가 예측하여 처리해주어야 한다.
RuntimeException과 RE가 아닌 것의 차이는?
예외의 종류에는 Checked Exception과 UnChecked Exception이 있다.
Checked Exception이란 반드시 예외처리를 해야 하는 예외이다. 예외 처리를 하지 않으면 컴파일 시점에서 예외처리를 하라는 에러가 발생한다.
UnChecked Exception은 반드시 예외처리를 하지 않아도 되는 런타임에 발생하는 예외이다. 이를 Runtime Exception이라고도 부른다. 예외처리를 강제하지 않기 때문에 개발자 스스로의 판단으로 예외처리 코드를 작성해야한다.
커스텀한 예외 만드는 방법
Custom Exception의 네가지 Best Practice
1. Always Provide a Benefit(항상 혜택을 제공하라)
커스텀 예외의 의도는 자바의 표즌 예외들로 표현할 수 없는 정보나 기능을 제공하는 것이다.
이것은 커스텀 예외를 만들 때 최우선으로 생각해야할 것이다. 만약 위의 의도가 없다면 JDK가 이미 제공하고 있는 방대한 수의 예외들과 비교했을 때 우리의 커스텀 예외는 어떠한 장점도 제공하지 못하게 된다.
어떠한 장점도 제공할 수 없는 커스텀 예외를 만드는 것보다 오히려 UnsupportedOperationException이나 IllegalArgumentException과 같이 표준 예외들 중 하나를 사용하는 것이 낫다.
2. Follow the Naming Convention(네이밍 컨벤션을 따라가라)
JDK가 제공하는 예외 클래스들을 보면 클래스의 이름들이 모두 "Exception:으로 끝난다는 것을 알 수 있다.
일반적인 네이밍 규칙으로 자바 생태계 전체에 적용되는 규칙이다.
3. Provide Javadoc Comments for Your Exception Class(예외 클래스에 대한 Javadoc 주석 제공)
기본적으로 API의 모든 클래스, 멤버변수, 생성자들에 대해서는 문서화하는 것이 일반적인 Best Practic다.
문서화 되지 않은 API들은 매우 사용하기가 어렵다.
클라이언트와 직접 관련된 메소드가 예외를 던지면 그 예외는 바로 API의 일부가 된다.
이는 잘 만들어진 Javadoc이 필요하다는 의미이다.
커스텀 예외의 Javadoc에는 예외가 발생할 수도 있는 상황과 예외의 일반적인 의미를 기술한다. 이는 다른 개발자들이 해당 API를 이해하도록 하고 예외 상황을 피하도록 돕기 위함이다.
4. Provider Constructor That Sets the Cause
Exception과 Runtime Exception은 예외의 원인을 기술하고 있는 Throwable을 받을 수 있는 생성자 메소드를 제공한다. 생성자를 통해 예외의 원인을 인자로 받는 것이 좋다.
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e, ErrorCode.INVALID_PORT_CONFIGURATION);
}
}
public class MyBusinessException extends Exception {
public MyBusinessException(String message, Throwable cause, ErrorCode code) {
super(message, cause);
this.code = code;
}
...
}
4가지 Best Practice를 적용시킨 CheckedException
/*
* 이것은 커스텀 CheckedException 입니다.
* 자바의 기본 예외로 표현할 수 없는 예외를 제공하기 위해 만들어졌습니다.
* */
public class CustomCheckedExceptionEx extends Exception {
public CustomCheckedExceptionEx() {
}
public CustomCheckedExceptionEx(String message) {
super(message);
}
public CustomCheckedExceptionEx(String message, Throwable cause) {
super(message, cause);
}
public CustomCheckedExceptionEx(Throwable cause) {
super(cause);
}
public CustomCheckedExceptionEx(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
class CustomCheckedExceptionTest {
public static void main(String[] args) throws CustomCheckedExceptionEx {
try {
// doSomething
} catch (Exception e) {
throw new CustomCheckedExceptionEx("커스텀 체크드 예외 발생!!", e);
}
}
}
4가지 Best Practice를 적용시킨 UnCheckedException
public class CustomUncheckedException extends RuntimeException {
public CustomUncheckedException() {
}
public CustomUncheckedException(String message) {
super(message);
}
public CustomUncheckedException(String message, Throwable cause) {
super(message, cause);
}
public CustomUncheckedException(Throwable cause) {
super(cause);
}
public CustomUncheckedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
class CustomUncheckedExceptionTest {
public static void main(String[] args) {
try {
// doSomething
} catch (RuntimeException e) {
throw new CustomUncheckedException("커스텀 언체크드 예외 발생!!", e);
}
}
}
ref {
- https://reakwon.tistory.com/155
- https://minzzang.tistory.com/11
- https://parkadd.tistory.com/69
}
'Programming > Java' 카테고리의 다른 글
[JAVA] ENUM (0) | 2022.03.21 |
---|---|
[JAVA]멀티쓰레드 프로그래밍 (0) | 2022.03.14 |
[JAVA]인터페이스 (0) | 2022.02.28 |
[JAVA] 패키지 (0) | 2022.02.21 |
[JAVA]상속 (0) | 2022.02.14 |
댓글