본문 바로가기
Sketch (Programming Language)/Java

Java의 정석 Chapter 8. 예외처리(exception handling)

by 생각하는 이상훈 2022. 5. 19.
728x90

프로그램 오류

1. 컴파일 에러: 컴파일 시에 발생하는 에러 (오타, 구문, 자료형 오류 체크)

2. 런타임 에러: 실행 시에 발생하는 에러

3. 논리적 에러: 실행은 되지만, 의도와 다르게 동작하는 것


예외 클래스의 계층구조

자바에서는 실행 시 발생할 수 있는 오류를 클래스로 정의하였다.

Exception클래스를 더 자세히 보면 다음과 같다.

-Exception클래스: 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외

-RuntimeException클래스: 프로그래머의 실수로 발생하는 예외


try-catch문

프로그램 실행시 발생할 수 있는 예외에 대하여 프로그래머가 미리 예외처리를 하여

실행 중인 프로그램의 갑작스러운 비정상 종료를 막고, 정상적인 실행상태를 유지할 수 있도록 하는 것이다.

 

try-catch문의 구조는 다음과 같다.

try{
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
// Exception1이 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
} catch (Exception2 e2) {
// Exception2가 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
}

다음 예시를 보면 이중구문이 가능함을 알 수 있다.

class ExceptionEx1 {
	public static void main(String[] args) 
   {
		try  {
			try	{	} catch (Exception e)	{ }
		} catch (Exception e)	{
			try	{	} catch (Exception e) { }	// 에러. 변수 e가 중복 선언되었다.
		} // try-catch의 끝

		try  {

		} catch (Exception e)	{

		} // try-catch의 끝
	}	// main메서드의 끝
}

 

다음은 산술연산과정에서 오류가 있을 때 발생하는 예외인 ArithmeticException에 대한 예시이다.

class ExceptionEx3 {
	public static void main(String args[]) {
		int number = 100;
		int result = 0;

		for(int i=0; i < 10; i++) {
			try {
				result = number / (int)(Math.random() * 10);
				System.out.println(result);
			} catch (ArithmeticException e)	{
				System.out.println("0");	
			} // try-catch의 끝
		} // for의 끝
	} 
}

 

멀티 catch블럭

try {
    ...
} catch (ExceptionA | ExceptionB e) {
	e.printStackTrace();
}

이와같이 '|'기호를 이용하여 여러 catch블럭을 하나의 catch블럭으로 합칠 수 있다.

 


finally블럭

예외의 발생여부에 관계없이 실행되어야할 코드를 포함시킬 목적으로 사용한다.

try{
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
// Exception1이 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
} finally {
	// 예외의 발생여부에 관계없이 항상 수행되어야하는 문장들을 넣는다.
    // finally블럭은 try-catch문의 맨 마지막에 위치해야한다.
}

예외가 발생하면 'try -> catch -> finally' 순으로 실행되고

예외가 발생하지 않으면 'try -> finally' 순으로 실행된다.


자동 자원 반환 (try-with-resources문)

try-catch문의 변형인 try-with-resources문은 입출력과 관련된 클래스를 사용할 때 유용하다.

class TryWithResourceEx {
	public static void main(String args[]) {

		try (CloseableResource cr = new CloseableResource()) {
			cr.exceptionWork(false); // 예외가 발생하지 않는다.
 		} catch(WorkException e) {
			e.printStackTrace();
		} catch(CloseException e) {
			e.printStackTrace();
		}
		System.out.println();
	
		try (CloseableResource cr = new CloseableResource()) {
			cr.exceptionWork(true); // 예외가 발생한다.
 		} catch(WorkException e) {
			e.printStackTrace();
		} catch(CloseException e) {
			e.printStackTrace();
		}	
	} // main의 끝
}

class CloseableResource implements AutoCloseable {
	public void exceptionWork(boolean exception) throws WorkException {
		System.out.println("exceptionWork("+exception+")가 호출됨");

		if(exception)
			throw new WorkException("WorkException 발생!!!");
	}

	public void close() throws CloseException {
		System.out.println("close()가 호출됨");
		throw new CloseException("CloseException발생!!!");
	}
}

class WorkException extends Exception {
	WorkException(String msg) { super(msg); }
}

class CloseException extends Exception {
	CloseException(String msg) { super(msg); }
}

예외 되던지기(exception re-throwing)

예외를 처리한 후에 인위적으로 다시 발생시키는 구문이다.

이는 try-catch문을 사용해서 예외를 처리해주고 catch문에서 필요한 작업을 행하고

throw문을 사용해서 예외를 다시 발생시키는 과정을 통해 작업한다.

재발생한 예외는 위 메서드를 호출한 메서드에게 전달되고 호출한 메서드의 try-catch문에서 예외를 또다시 처리한다.

이 방법은 하나의 예외에 대해서 예외가 발생한 메서드와 이를 호출한 메서드 양쪽 모두에서 처리해야 할 작업이 있을때

사용하는 방법이다.

class ExceptionEx17 {
	public static void main(String[] args) 
	{
		try  {
			method1();		
		} catch (Exception e)	{
			System.out.println("main메서드에서 예외가 처리되었습니다.");
		}
	}	// main메서드의 끝

	static void method1() throws Exception {
		try {
			throw new Exception();
		} catch (Exception e) {
			System.out.println("method1메서드에서 예외가 처리되었습니다.");
			throw e;			// 다시 예외를 발생시킨다.
		}
	}	// method1메서드의 끝
}

이런식으로 이용할 수 있다.

 

 

 

 

 

 

728x90