Java 예외처리(Exception)의 종류와 예외 처리(Exception Handling)

이명신·2023년 1월 11일
0

java

목록 보기
1/2

이번 포스팅에서는
자바에서 예외처리에 쓰이는 try, catch, finally 와 throw 구문에 대해 알아보려 하고 그 이전에
예외란 무엇인지 예외처리란 무엇인지에 대해 설명해보겠습니다.

예외(Exception)


프로그램을 실행하다 보면 어떤 원인 때문에 비정상적인 동작을 일으키며 프로그램이 종료되는 상황을 보신적 있으실 겁니다. 이때 우리는 프로그램이 오류가 발생했다고 합니다. 에러의 종류는 우리가 컴파일할때 발생할 수 있는 컴파일 오류와 실행 중 발생되는 런타임 오류 두 종류로 보고 있습니다. 바로 에러(Error)와 (Exception)으로 말이죠.

에러는 프로그램이 코드로 복구할 수 없는 오류를 의미하고 예외는 프로그래머가 직접 예측하여 막을 수 있는 처리가능한 오류라고 보시면 됩니다. 예를 들어 메모리가 부족한 경우 프로그래머가 직접 제어할 수 없으므로 이런 경우는 메모리 부족(OutOfMemory) 에러가 발생하고 함수 호출이 많아 스택이 쌓일 경우에는 StackOverFlowError가 발생할 수 있습니다.

그런데 아래의 코드처럼 어떤 수를 0으로 나눈다면 어떤 상황이 발생할까요?

int a,b;
a=10;
b=0;

int c=a/b;
System.out.println(c);

어떤 수를 0으로 나술수 없기 때문에 오류를 내보내게 됩니다.

Exception in thread "main" java.lang.ArithmeticException: /by zero
	at aa.Main.main(Main.java:11)

하지만 조건문을 통해서 우리는 0으로 못 나누게 할 수 있죠. 이처럼 우리가 예측가능한 상황에서 오류를 제어할 수 있는것이 예외입니다. 이렇게 예측가능한 오류를 제어하는것을 예외처리(Exception Handler) 라고 합니다.

예외 처리(Exception Handler)

1. try, catch

예외가 발생했을 때 우리는 try,catch,finally 라는 키워드로 예외를 처리할 수 있거나 메소드를 호출한 곳으로 던질 수 있습니다. 한 가지 중요한 점은 자바에서 모든 예외는 Exception이라는 클래스를 상속 받습니다. Exception의 상속 트리를 아래에 간략하게 나타내었습니다.

예외 처리하는 방식은 이렇습니다.

tyr{
	//예외가 발생한 코드
}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 클래스는 모든 예외의 부모이기 때문에 IOException이 발생하더라고 catch(Exception e) 블록에 걸려 처리됩니다.

finally 블록 : 여기서는 예외가 발생하건 말건 무조건 수행되는 코드가 쓰여집니다. 임시 파일의 삭제 등 뒷정리 코드가 쓰입니다.

이것을 이용하여 우리는 위의 코드를 예외처리할 수 있습니다.

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 실행");
	}
}

printStackTrace() 메서드는 어느 부분에서 예외가 발생했는지 알려주는 추적로그를 보여줍니다. Exception이 발생했을때 기본 동작이죠. 결과는 아래와 같은 것을 알 수 있습니다.

ArithmeticException 발생
java.lang.ArithmeticException: / by zero
	at aa.Main.main(Main.java:11)		//Main.java에서 11번째 줄에서 발생했다는 printStackTrace
finally 실행

2.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를 나눈 후에 출력하는 역할을 하는데, 이 나누기 부분에서 우리는 예외가 발생할 수 있음을 알았습니다. 그래서 try, catch로 예외 처리를 해야하지만, divide()를 호출하는 부분에서 처리하기를 원합니다. 왜냐면 divide를 호출한 곳에서 발생한 다음의 처리를 divide() 메소드가 정하기 않기 때문입니다. 예를 들어 main메소드에서는 예외가 발생하면 다시 divide()를 호출하거나 프로그램을 끝내거나, b이 값을 다시 입력받거나 해야하기 때문이고, divide()메소드가 그 결정을 할 수 없다는 의미입니다. 그래서 throws ArithmeticException을 divide를 호출한 main에다가 던지는 것(throw)입니다. 여기서 예외를 던지는 방법은 아래와 같습니다.

throw 예외객체
ex) throw new Exception("예외 발생!")

예외를 발생시키는 키워드는 throw 입니다. 이때 main은 그 예외를 처리하기 위해 try, catch 블록을 쓰면 됩니다. 아래처럼 말이죠

try{
	divide(a,b);
}catch(ArithmethicException e){
	e.getMassage();
    e.printStackTrace();
}

throws 키워드로 처리되어야 할 예외가 여러개 존재한다면 쉼표로 끊어서 예외를 넘겨줄 수 있습니다. 그 결과는 아래와 같습니다.

java.lang.ArithmeticException: 0으로 나눌 수는 없다니까?
	at aa.Main.divide(Main.java:8)
	at aa.Main.main(Main.java:17)

이상으로 자바 Exception에 대한 기본 개념과 예외 처리하는 방법을 마치도록 하겠습니다.

0개의 댓글