[Study] 자바 9주차 과제
9주차 과제입니다.
자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
try, catch, finally
package exception;
public class Ex_Exception {
public static void main(String[] args) {
try {
System.out.println("A");
System.out.println(1 / 0); //예외 발생
System.out.println("B"); //예외 발생 후 바로 catch 문으로 가기 때문에 실행 안됨
}catch (ArithmeticException e) {
System.out.println("C");
System.out.println(e.getMessage()); //해당 throwable 객체에 대한 자세한 내용
e.printStackTrace(); //해당 throwable 객체와 표준 오류 스트림에서 해당 객체의 스택 트레이스(stack trace)를 출력함
//catch 문 안에 예외처리도 가능
try {
System.out.println("D");
System.out.println(2 / 0);
}catch (ArithmeticException e1) {
System.out.println("E");
}
}catch (Exception e) {
//catch 문 여러 개 작성 가능
System.out.println("F");
}finally {
//예외처리와 관련없이 무조건 실행됨
System.out.println("G");
}
}
}
자바에서는 프로그램이 실행되는 도중 발생하는 예외를 처리하기 위해 try / catch / finally 문을 사용할 수 있습니다.
- try 블록: 기본적으로 맨 먼저 실행되는 코드로 여기에서 발생하는 예외는 catch 블록에서 처리됩니다.
- catch 블록: try 블록에서 발생한 예외 코드나 예외 객체를 인수로 전달받아 그 처리를 담당합니다.
- finally 블록: 이 블록은 try 블록에서 예외가 발생하건 안 하건 맨 마지막에 무조건 실행됩니다.
catch 블록과 fianlly 블록은 선택적인 옵션으로 반드시 사용할 필요는 없습니다.
따라서 사용할 수 있는 모든 적합한 try 구문은 다음과 같습니다.
1. try / catch
2. try / finally
3. try / catch / ... / finally
Multicatch block
JDK 1.7부터 여러 catch block을 하나로 합칠 수 있게 되었습니다.
package exception;
public class Ex_Exception {
public static void main(String[] args) {
try {
//try문 코드
}catch (IllegalArgumentException | ArithmeticException e) {
//catch문 코드
}
}
}
단, 이 때 나열된 예외 클래스들이 부모-자식 관계에 있다면 오류가 발생합니다.
왜냐하면, 자식 클래스로 잡아낼 수 있는 예외는 부모 클래스로도 잡아낼 수 있기 때문에 사실상 코드가 중복된 것이나 마찬가지이기 때문입니다. 이 때, 컴파일러는 중복된 코드를 제거하라는 의미에서 에러를 발생시킵니다.
package exception;
public class Ex_Exception {
public static void main(String[] args) {
try {
//try문 코드
}catch (IllegalArgumentException | ArithmeticException e) {
//두 예외 클래스가 부모-자식 관계라서 에러 발생
//catch문 코드
}
}
}
throw, throws
package exception;
public class Ex_Exception {
public static void main(String[] args) {
try{
throw new Exception("예외 발생");
}catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
//출력
//예외 발생
자바에서는 throw 키워드를 사용하여 강제로 예외를 발생시킬 수 있습니다.
위 예제처럼 생성자에 전달된 문자열은 getMessage() 메소드를 사용하여 오류 메시지로 출력할 수 있습니다.
메소드 선언부에 throws 키워드를 사용하여 해당 메소드를 사용할 때 발생할 수 있는 예외를 미리 명시할 수도 있습니다.
이렇게 하면 해당 메소드를 사용할 때 발생할 수 있는 예외를 사용자가 충분히 인지할 수 있으며, 그에 대한 처리까지도 강제할 수 있습니다.
따라서 더욱 안정성 있는 프로그램을 손쉽게 작성할 수 있도록 도와줄 수 있습니다.
package exception;
public class Ex_Exception {
public static void main(String[] args) {
try {
handlingException();
}catch (Exception e) {
System.out.println("main 메소드에서 예외가 처리됨");
}
}
static void handlingException() {
try {
throw new Exception();
}catch (Exception e) {
System.out.println("호출된 메소드에서 예외가 처리됨");
}
}
}
//출력
//호출된 메소드에서 예외가 처리됨
이 때 호출된 메소드의 try / catch 문을 생략하면 컴파일 오류가 발생합니다.
또한, 이 메소드를 호출한 main() 메소드는 호출된 메소드에서 예외가 발생한 사실을 알 수 없습니다.
package exception;
public class Ex_Exception {
public static void main(String[] args) {
try {
handlingException();
}catch (Exception e) {
System.out.println("main 메소드에서 예외가 처리됨");
}
}
static void handlingException() throws Exception {
throw new Exception();
}
}
//출력
//main 메소드에서 예외가 처리됨
thorws 키워드를 사용하여 호출된 메소드에서 발생한 예외를 호출한 메소드로 넘김으로써 호출된 메소드에는 try / catch 문을 생략할 수 있습니다. 그리고 호출된 메소드에서 발생한 예외를 해당 메소드를 호출한 main() 메소드에서 처리할 수 있게 됩니다.
자바가 제공하는 예외 계층 구조
모든 예외 클래스는 Throwable 클래스를 상속받고 있으며, Throwable의 최상위 클래스 Object의 자식 클래스입니다.
Exception은 CheckedException과 UncheckedException으로 구분할 수 있으며, Exception 자식 클래스 중 RuntimeException은 UncheckedException, 그 외의 Exception은 CheckedException이라고 합니다.
이를 구분하는 가장 큰 기준은 "꼭 처리를 해야하느냐" 입니다. RuntimeException 이외의 Exception이 발생할 가능성이 있는 코드는 반드시 예외 처리를 해주어야 합니다.
RuntimeException과 RE가 아닌 것의 차이는?
CheckedException | UncheckedException |
반드시 예외 처리를 해야함 | 명시적인 처리를 강제하지 않음 |
컴파일 단계에서 확인 | 실행단계에서 확인 |
IOException FileNotFoundException ... 외부적인 영향으로 발생할 수 있는 예외 |
RuntimeException | -- ArithmeticException | -- NullPointerException ... 실행 중 발생되는 예외 |
Exception과 Error의 차이는?
자바 프로그렘을 작성할 때 자바 문법에 맞지 않게 코드를 작성하고 컴파일하려고 하면, 자바 컴파일러는 문법 오류(syntax error)를 발생시킵니다.
또한, 자바 문법에는 맞게 작성되었다 하더라도 프로그램이 실행되면서 예상하지 못한 오류가 발생할 수 있습니다.
이렇게 컴퓨터 시스템이 동작하는 도중에 예상하지 못한 사태가 발생하여 실행 중인 프로그램이 영향을 받는 것을 오류(error)와 예외(exception) 두 가지로 구분할 수 있습니다.
오류(error)는 시스템 레벨에서 프로그램에 심각한 문제를 야기하여 실행 중인 프로그램을 종료시킵니다.
이러한 오류는 개발자가 미리 예측하여 처리할 수 없는 것이 대부분이므로, 오류에 대한 처리는 할 수 없습니다.
하지만 예외(exception)는 오류와 마찬가지로 실행 중인 프로그램을 비정상적으로 종료시키지만, 발생할 수 있는 상황을 미리 예측하여 처리할 수 있습니다.
따라서 개발자는 예외 처리(exception handling)를 통해 예외 상황을 처리할 수 있도록 코드의 흐름을 바꿀 필요가 있습니다.
커스텀한 예외 만드는 방법
class SubwayProgramException extends IllegalArgumentException {
private static final String PREFIX = "[ERROR] ";
private static final String NEWLINE = "\n";
public SubwayProgramException(String errorMessage) {
super(NEWLINE + PREFIX + errorMessage);
}
}
public class Application {
private static final String errorMessage = "커스텀 에러";
public static void main(String[] args) {
try {
throw new SubwayProgramException(errorMessage);
}catch (SubwayProgramException e) {
System.out.println(e.getMessage());
}
}
}
//출력
//[ERROR] 커스텀 에러
기존에 정의된 예외 클래스 외에 필요에 따라 새로운 예외를 정의할 수 있습니다.
Exception 클래스를 상속받거나, 필요에 따라 알맞은 예외 클래스를 상속받아 만듭니다.
getMessage() 메소드에 의해 출력되는 내용도 생성자를 통해 커스텀할 수 있습니다.
References