티스토리 뷰

▶Try-Catch문 - 예외 처리/커스텀 예외/예외던지기

이번 글에서는 자바의 예외 처리에 대해 알아보도록 하겠습니다.

 

🔎 예외 처리 ?


예외 처리란 컴파일 시, 빌드 시, 런타임 시 오류가 발생하면 여러 가지 이유로 오류가 발생할 수 있슶니다.

보통 오류가 발생하지 않도록 제어문(ex. if문)을 사용하지만, 제어문을 사용할 수 없을 경우 예외 처리 문법을 사용합니다.

 

📌 오류 발생 ?

우리가 소스코드를 실행 했는데.. 콘솔창에 빨간색 글씨로 오류가 발생했다면

그 오류는 어디서 왜 발생한 걸까요?

 

오류가 발생했다는 건 그 오류 객체(필드)가 메모리에 올라갔다는 것입니다.

즉, 오류 객체에게도 주소값이 생겼다는 것인데요.

이때 이 주소값을 담을 곳이 없으면 즉시 강제 종료 되도록 되어 있습니다.

 

이때 그 오류 객체의 주소값이 날아왔을 때 담을 곳이 없으면 강제 종료 하는 것이고,

그 주소를 잡아서 저장해 놓은 것이 바로 이제 알아볼 try catch문의 catch입니다.

따라서 그 주소를 잡아 저장해 놓아서 처리를 하면 강제 종료가 아니라 그 catch문에 있는 코드가 실행될 것입니다.

 

📌 예외 처리 문법

try {

    오류가 발생할 수 있는 문장
    
} catch(Exception e1) {

    오류 발생 시 실행할 문장
    
} catch(Exception e2) {
    
    오류 발생 시 실행할 문장
}

} finally {

    catch에서 잡히지 않는 오류가 있더라도 무조건 실행
}

기본적인 try catch 구문의 구조인데요.

try문에서 Exception 예외가 발생할 경우 catch(Exception e)로 빠져서 그 안의 실행문을 실행합니다.

 

즉, 위에서 오류 객체가 날아오면 해당하는 예외를 잡으려고 기다리는 catch문으로 빠져서 그 안의 실행문을 실행하는 것입니다.

 

마지막의 finally블럭은 try-catch문과 함께 예외발생 여부와 관계없이 무조건 실행되어야 할 코드를 적습니다.

필수는 아니며 마지막에 선택적으로 덧붙여 사용합니다.

 

참고!

finally 블록은 보통 자원이나 DB에 커넥션 한 경우, 파일 닫기, 연결 닫기(close) 등과 같은 정리 코드를 넣는데 사용합니다.

 

📌 예제 코드

길이가 5인 배열을 선언했는데 그것보다 넘는 인덱스에 값을 추가하는 경우를 try-catch 문으로 예외를 처리해 보겠습니다.

int[] arData = new int[5];

try {
    arData[5] = 10;
} catch (IndexOutOfBoundsException e) {
    // 날아온 에러와 위에 작성한 에러 타입이 다르면 못잡음
    e.printStackTrace(); // 오류추적 -> 몇 번째 줄에서 무슨 오류가 났는지
    System.out.println(e.getMessage()); // 오류 메시지 출력
} finally {
    // 위에서 에러를 못잡더라도 무조건 실행됨
    System.out.println("반드시 실행되어야 하는 문장");
}

// try-catch문에서 에러를 잡았다면 위에서 중단되지 않고
// 밑에 문장들도 실행
// 위에서 에러를 잡지 못했다면
// 즉시 중단되어 try-catch 문 아래 문장들은 실행 X
System.out.println("이건 try-catch 밖의 문장!");

위 코드에서 catch문에서 오류 객체를 잡았기 때문에 코드가 중단되지 않아 try-catch 문 아래 코드도 실행될 수 있었습니다.

출력 화면

이번에는 오류 객체를 잡지 못했다면 어떻게 될까요?

int[] arData = new int[5];

try {
    arData[5] = 10;
} catch (NumberFormatException e) {
    // 날아온 에러와 위에 작성한 에러 타입이 다르면 못잡음
    e.printStackTrace(); // 오류추적 -> 몇 번째 줄에서 무슨 오류가 났는지
    System.out.println(e.getMessage()); // 오류 메시지 출력
} finally {
    // 위에서 에러를 못잡더라도 무조건 실행됨
    System.out.println("반드시 실행되어야 하는 문장");
}
// 위에서 에러를 잡지 못했다면
// 즉시 중단되어 try-catch 문 아래 문장들은 실행 X
System.out.println("이건 try-catch 밖의 문장!");

이번에는 catch문에서 에러를 잡지 못해서 try-catch 문 아래 코드는 실행되지 못했습니다.

에러를 잡지 못했기 때문에 즉시 중단되었기 때문입니다.

그렇지만 finally 블럭에 작성한 코드는 에러를 잡지 못해도 실행된 것을 확인할 수 있었습니다.

출력 화면

728x90
SMALL

📌 예외 처리 상황 정리

1️⃣ 예외가 try 블럭 안에서 발생하지 않은 경우

→ try-catch문을 거치지 않는다.

 

2️⃣ try 블럭 안에서 발생한 예외가 catch 문에서 잡힌 경우

→ catch 블럭 안 코드를 실행한다. 멈추지 않고 try-catch 문 아래 코드를 실행해 나간다.

 

3️⃣ try 블럭 안에서 발생한 예외가 catch문에서 잡히지 못한 경우

→ finally 블럭이 있다면 실행되고 즉시 중단된다. 바로 중단되기 때문에 try-catch 아래 문장들은 모두 실행되지 못한다.

 

📌 예외 처리 관련 메소드

📍 printStackTract()

예외 발생 당시의 호출 스택(Call Stack)에 있었던 메소드의 정보와 예외 메세지를 콘솔화면에 출력합니다.

리턴값은 없으며, 이 메소드를 호출하면 메소드가 내부적으로 예외 결과를 화면에 출력합니다.

참고로, printStackTrace는 가장 자세한 예외 정보를 제공합니다.

 

📍 getMessage()

발생한 예외 클래스의 인스턴스에 저장된 메세지를 얻을 수 있습니다.

따라서 자세하게 몇번째 줄에서 오류가 발생했고 하는 상세한 정보는 알려주지 않습니다.

 

🔎 커스텀 예외 만들기 & 예외 던지기


직접 예외를 발생시키기 위해서는 예외 던지기를 사용해야 하는데요.

이때에는 생성자 호출 전에 throw 키워드를 사용합니다.

 

❓ 예외를 왜 커스텀하는가

 

직접 예외를 사용하는 경우는

기본적으로 제공하는 예외가 아닌 특정 상황에서 직접 예외를 만들어야 하는 상황이 생길 때인데요.

 

이때 Exception 또는 RuntimeException을 상속받아서 예외 클래스를 선언해 주어야 합니다.

 

📌 부모가 Exception일 때와  RuntimeException일 때

위에서 에러가 발생하는 과정에서 에러 객체 이야기를 했었는데요.

이 에러 객체에게도 부모 클래스가 있는데요.

 

경우는 2가지 입니다.

1️⃣ Excepton을 상속받았다

Exception은 컴파일러가 체크를 하기 때문에 예외 처리를 강제로 해야 합니다.

 

2️⃣ RuntimeException을 상속받았다

RuntimeException은 컴파일러가 체크하지 않기 때문에 예외 처리를 선택할 수 있습니다.

 

📌 예제 코드로 알아보자

이번에는 "바보"라는 문자열이 들어오면 예외로 처리해서 *로 콘솔에 다시 찍는 프로그램을 작성해 보려고 합니다.

그렇다면 "바보"라는 문자열이 들어온다면 에러를 발생시켜서(던지기) try-catch문이 실행되도록 하려고 합니다.

 

따라서 이 에러를 던지기 위해서는 기본적으로 제공하는 예외가 아닌 직접 예외를 발생시켜서 처리해야 할 것 같습니다.

 

📄 BadWordException.java 파일 "Exception 상속받음"

public class BadWordException extends Exception {
    public BadWordException(String message) {
        // 예외 발생 원인(예외 메시지)을 전달하기 위해 String 타입의 매개변수를 갖는 생성자
        super(message); // 부모 생성자에 message를 전달
    }
}

Exception을 상속받아 직접 예외를 작성해 주었습니다.

말이 예외지 Class로 작성합니다.

 

예외가 발생할 때 예외 메세지를 전달하기 위해 String 타입의 매개변수를 갖는 생성자를 호출합니다.

 

📄 Chatting.java 파일

public class Chatting {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        String message = null;
        
        System.out.print("메시지: ");
        message = sc.nextLine();
        
        if (message.equals("바보")) {
            try {
                // 커스텀한 클래스의 생성자에 String 매개변수를 전달하면
                // 그걸 예외 메세지로 콘솔창에 출력해주게 됨
                throw new BadWordException("비속어는 사용할 수 없습니다.");
            } catch(BadWordException e) {
                for (int i=0; i<message.length(); i++) {
                    System.out.print("*");
                }
            }
        }
    }
}

try 블록 안에서 예외가 발생할 가능성이 있는 코드를 작성해서 catch로 예외를 잡는다고 했습니다.

그런데 위 코드에서는 아예 try문에서 예외를 발생시키니까 당연히 catch로 넘어가며 그대로 catch로 잡도록 했으므로

catch 블록 안에 코드가 실행 될 것입니다.

출력 화면

그렇다면 Exception이 아니라 RuntimeException을 상속받는 경우는 어떻게 다를까요?

 

📄 BadWordException.java 파일

public class BadWordException extends RuntimeException {
    public BadWordException(String message) {
        super(message); // 부모 생성자에 message를 전달
    }
}

이번에는 RuntimeException을 상속받았습니다.

위에서 말했다싶이 RuntimeException은 컴파일러가 체크하지 않아서 예외 처리를 선택적으로 할 수 있습니다.

 

즉, Exception을 상속받았을 때는 try-catch문을 사용하지 않는다면 에러가 발생한다는 말과 같습니다.

Exception을 상속받았는데, try-catch문을 사용하지 않았을 때

❓ 이걸 왜 생각해야할까

만약 에러가 발생하면 바로 프로그램을 중단하고 싶은 경우도 있을 것입니다.

만약 이러한 경우에 try-catch문을 사용하면 중단되지 않고 에러를 잡고 쭉 아래 코드를 실행할 것입니다.

중단 없이요.

 

✨ 따라서 에러가 발생해서 그 즉시 프로그램을 중단하고 싶다면 RuntimeException을 상속받아야 합니다.

 

만약 "바보"라는 문자열이 들어오면 바로 계정이 중지되면서 프로그램이 중단되도록 코드를 작성해 보겠습니다.

 

📄 Chatting.java 파일

public class Chatting {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        String message = null;
        
        System.out.println("메세지: ");
        messgaeg = sc.nextLine();
        
        if(message.equals("바보")) {
            System.out.println("계정 정지");
            throw new BadWordException("비속어는 사용할 수 없습니다.");
        }
        System.out.println("선플을 작성하셨군요!");
    }
}

실행 화면

정리!!

✨ 예외가 발생하면 잡아서 처리하고 코드를 계속 실행하고 싶다 → Exception 상속

✨ 예외가 발생하면 즉시 코드 중단하고 싶다 → RuntimeException 상속

728x90
LIST
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함