예외(Exception) 처리하기
프로그램의 실행 도중에 발생하는 에러는 어쩔 수 없지만, 예외는 프로그래머가 이에 대한 처리를 미리 해줘야 한다.
예외처리(Exception Handling)란, 프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 것이다.
또한 예외처리의 목적은 예외의 발생으로 인한 실행 중인 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지할 수 있도록 하는 것이다.
발생한 예외를 처리하지 못하면, 프로그램은 비정상적으로 종료되며, 처리되지 못한 예외는 JVM의 '예외처리기(UncaughtExceptionHandler)'가 받아서 예외의 원인을 화면에 출력한다.
try - catch 문
예외를 처리하기 위해서는 try-catch문을 사용한다.
try{
// 에러가 발생할 가능성이 있는 로직을 넣는다.
}catch(Exception1 e1){
// Exception1 발생했을 경우, 이를 처리하기 위한 로직을 적는다.
}catch(Exception2 e2){
// Exception2 발생했을 경우, 이를 처리하기 위한 로직을 적는다.
}catch(Exception3 e3){
// Exception3 발생했을 경우, 이를 처리하기 위한 로직을 적는다.
}
하나의 try블럭 다음에는 여러 종류의 예외를 처리할 수 있도록 하나 이상의 catch블럭이 올 수 있으며, 이 중 발생한 예외의 종류와 일치하는 단 한개의 catch 블럭만 수행된다.
class ExceptionEx{
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"); // ArithmeticException이
// 발생하면 실행되는 코드
}
}
}
}
try-catch문에서의 흐름
try-catch 문에서, 예외가 발생한 경우와 발생하지 않았을 때의 흐름(문장의 실행순서)이 달라진다!
✔︎ try 블럭 내에서 예외가 발생한 경우
1. 발생한 예외와 일치하는 catch 블럭이 있는지 확인
2. 일치하는 catch 블럭을 찾게 되면, 그 catch 블럭 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 만일 일치하는 catch블럭을 찾지 못하면 예외는 처리되지 못한다.
✔︎ try 블럭 내에서 예외가 발생하지 않은 경우
1. catch블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다.
public class Exception {
public static void main(String[] args) {
int a, b, c;
try {
// ...
} catch (NumberFormatException e) {
System.out.println("숫자로 변환할 수 없습니다.");
} catch (ClassNotFoundException e) {
System.out.println("클래스가 존재하지 않습니다.");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("실행 매개값의 수가 부족합니다.");
} catch (IOException e) {
System.out.println("입력값이 잘못 되었습니다.");
} catch (NullPointException e) {
System.out.println("NULL을 참조하고 있습니다.");
} ...
}
}
그렇다면 위와같이 꼭 예외처리를 각각 항목별로 선언해야하는가?
그런 것은 아니다. 예외 클래스가 너어어어무 많아서 전체 다 선언할수는 없다. 클래스의 상속 관계를 이용하여 예외클래스의 상위 클래스인
Exception 클래스 타입을 catch문에 선언하면, catch문 단 하나로 모든 예외 발생을 처리할 수 있다.
멀티 catch 블럭
JDK 1.7부터 여러 catch블럭을 '|' 기호를 이용해서, 하나의 catch블럭으로 합칠 수 있게 되었다. 이를 '멀티 catch블럭'이라 한다.
아래의 코드에서 알 수 있듯이 멀티 catch블럭을 사용하면 중복된 코드를 줄일 수 있다.
try {
// ...
} catch (NullPointException | ArrayIndexOutOfBoundsExcetion e) {
// ...
}
만일 멀티 catch블럭의 '|' 기호로 연결된 예외 클래스가 조상과 자손의 관계에 있다면 컴파일 에러가 발생한다.
try {
// ...
} catch (ParentException | ChildException e) {
// ...
}
왜냐하면, 두 예외 클래스가 조상과 자손의 관계에 있다면, 그냥 조상 클래스에만 써주는 것과 똑같기 때문이다.
try-catch-finally 문
try{
// 에러가 발생할 가능성이 있는 로직을 넣는다.
}catch(Exception1 e1){
// Exception1 발생했을 경우, 이를 처리하기 위한 로직을 적는다.
}finally{
// 항상 실행!!!!
}
위에서 정리한 try-catch문에서 finally문이 추가되었는데..
기존에 try-catch에서는 프로그램 수행 도중 예외가 발생하면 프로그램이 중지되거나, 예외 처리에 의해 catch 구문으로 빠져버린다.
하지만 어떠한 예외가 발생하더라도 꼭 실행되어야하는 부분이 있다면 finally문으로 처리가 가능하다!
예외가 발생한 경우에는 try -> catch -> finally 순서로 실행되고
에외가 발생하지 않은 경우에는 try -> finally 순으로 실행된다.
예외 메세지 출력
예외가 발생했을 떄 생성되는 예외 클래스의 인스턴스에는 발생한 예외에 대한 정보가 담겨져 있으며, getMessage()와 printStackTrace()를 통해서 이 정보들을 얻을 수 있다.
printStatckTrace() - 예외발생 당시의 호출 스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.
getMessage() - 발생한 예외 클래스의 인스턴스에 저장한 메시지를 얻을 수 있다.
printStackTrace() 는 프로그램의 내부 요소를 자세하게 추적하여 오류 메세지를 내보이기에 이를 외부에 노출시키면 보안적인 문제가 될 수 있으니 관계자만 확인 할 수 있도록 만들어 주는 것이 좋다.
try{
...
System.out.println(0/0); // ArithmeticException 예외 발생
...
} catch(ArithmeticException e){ // e는 해당하는 에러의 예외정보가 담겨 있는 참조 변수 이다
// 에러 메세지
System.out.println(aa.getMessage()); // by zero
// 상세한 에러 추적 메세지
e.printStackTrace(); // java.lang.ArithmeticException: / by zero at MyClass.main(MyClass.java:5)
}
#참고자료
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com
Inpa Dev 👨💻
성장 욕구가 가파른 초보 개발자로서 공부한 내용을 쉽게 풀어쓴 기술 개발자 블로그를 운영하고 있습니다.
inpa.tistory.com
'개발 > JAVA' 카테고리의 다른 글
[JAVA] 예외(Exception)와 에러(Error) (0) | 2023.03.23 |
---|---|
[JAVA] 익명 클래스(Anonymous class) (0) | 2023.03.23 |
[JAVA] 내부 클래스(inner class) (0) | 2023.03.23 |
[JAVA] 인터페이스(Interface) vs 추상클래스(Abstract Class) 비교 (0) | 2023.03.06 |
[JAVA] 인터페이스(Interface) 총 정리 (0) | 2023.03.01 |