오늘의하루

[자바의 정석] 예외처리 본문

JAVA

[자바의 정석] 예외처리

오늘의하루_master 2022. 10. 19. 18:31

예외처리 (Exception handling)

프로그램 오류에는 컴파일 에러, 런타임 에러로 나눌 수 있습니다.

  • 런타임 에러에는 다시 에러(Error)와 예외(Exception)로 나뉩니다.
종류 의미
컴파일 에러 컴파일 할 때 발생하는 에러
런타임 에러 실행 할 때 발생하는 에러

런타임 에러

종류 의미
에러 (Error) 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
예외 (Exception) 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류
예외의 경우는 꼭 예외 처리를 해줘야한다.

예외 처리는 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것을 말한다.

예외처리 구문

예외를 처리하려면 try - catch문을 사용해야 한다.

try{
    // 예외가 발생할 가능성이 있는 문장
} catch(Exception1 e1){
    // Exception1에 해당하는 예외가 발생하면 이를 처리할 문장
} catch(Exception2 e2){
    // Exception2에 해당하는 예외가 발생하면 이를 처리할 문장
} catch(Exception3 e3){
    // Exception3에 해당하는 예외가 발생하면 이를 처리할 문장
}

try - catch문의 흐름

try 블록 내에서 예외가 발생한 경우

  1. 발생한 예외와 일치하는 catch블록이 있는지 확인한다.
  2. 일치하는 catch블록이 있다면 해당 catch블록에 있는 문자를 수행한다.
    • 만약 일치하는 catch블록이 없다면 예외처리가 되지 않았기 때문에 프로그램이 실행되지 않는다.
  3. try-catch문 전체를 빠져나오고 다음 코드부터 실행한다.

try블록 내에서 예외가 발생하지 않은 경우

  1. catch블록을 모두 무시하고 빠져나오고 다음 코드부터 실행한다.
public class ExceptionTest{
    public static void main(String[] args){
        System.out.println(1);
        System.out.println(2);
        
        try{
            System.out.println(3);
            System.out.println(4);
            System.out.println(0/0); // 예외 발생
            System.out.println(5);
        } catch(Exception e){
            System.out.println(6);
        }
        
        System.out.println(7);
    }
}

// 결과 1 2 3 4 6

예외 발생시키기

예외는 고의로 발생시킬 수 있다.

1. new 연사자를 이용해서 발생시키려는 예외 클래스의 객체를 만든다.
2. 키워드 throw를 통해서 예외를 발생시킨다.
try{
    Exception e = new Exception("고의로 발생시키는 예외");
    throw e;
    // 위 두줄을 한줄로 줄이면 throw new Exception("고의로 발생시키는 예외"); 가 된다.
} catch(Exception e){
    System.out.println("에러 메시지 : " + e.getMessage());
    e.printStackTrace();
}
System.out.println("프로그램이 정상 종료되었습니다.");


// 결과
// 에러 메시지 : 고의로 발생시키는 예외
// java.lang.Exception : 고의로 발생시키는 예외 at public클래스이름.main(public클래스이름.java:예외 발생 위치)
// 프로그램이 정상 종료되었습니다.

예외 클래스의 계층구조

예외 클래스는 크게 예외처리가 필수인 그룹과 예외처리가 선택인 그룹으로 나눌 수 있습니다.

RuntimeException 클래스 그룹 : 프로그래머의 실수로 발생하는 예외(예외처리 필수)
Exception 클래스 그룹 : 사용자의 실수와 같은 외적인 요소로 발생하는 예외(예외처리 선택)

Exception

  • IOException (입출력 예외)
  • ClassNotFoundException (클래스가 존재하지 않는다.)
  • ...
  • RuntimeException
    • ArithmeticException (산술 계산 예외 ) 예를 들어 5/0
    • ClassCastException (형 변환 예외)
    • NullPointerException (널 포인트 예외) 예를 들어 "String str = null; str.length;"
    • ...
    • IndexOutOfBoundsException (배열 범위를 벗어난 예외)
예외 클래스의 최고 조상인 Exception은 반드시 마지막 catch블록에 사용해야 한다.
만약 첫 번째 때 사용한다면 정확히 어떤 예외인지 알 수 없기 때문이다.
System.out.println(1);
System.out.println(2);
try{
    System.out.println(3);
    System.out.println(0/0); // ArithmeticException 발생
    System.out.println(4);
} catch(ArithmeticException ae){
    System.out.println("true");
    System.out.println("ArithmeticException");
} catch(Exception e){
    System.out.pritnln("Exception");
}
System.out.println(6);

// 결과 1 2 3 true ArithmeticException 6

finally 블록

예외의 발생 여부와 처리 여부에 관계없이 무조건 실행되어야 하는 코드를 넣는 곳이다.

  • 예외 발생 시에는 "try > catch > finally" 순서로 실행
  • 예외 미발생시에는 "try > finally" 순서로 실행
  • try 혹은 catch 블록에서 return문을 만나도 finally블록은 수행된다.
try{
    // 예외 발생 가능성이 있는 문장
} catch(Exception1 e1){
    // Exception1 예외처리를 위한 문장
} finally{
    // 예외 발생여부에 관계없이 실행되는 문장
    // finally 블록은 맨마지막에 위치해야한다.
}

메서드에 예외 선언하기

예외처리 방법 중 하나이며 실제로는 예외를 처리하는 게 아닌 메서드를 호출한 곳으로 예외를 전달시키는 것입니다.

  • 호출한 곳에서 예외를 처리해야만 할 때 사용됩니다.
// 사용방법
void method() throws Exception1, Exception2, ..., ExceptionN{
    // 메서드 수행할 문장
}
import java.io.*;

public class ExceptionTest{
    public static void main(String[] args){
        try{
            File f = createFile(args[0]); // 메서드가 전달하고자 하는 예외는 이쪽으로 전달된다.
            System.out.println(f.getName() + "파일이 성공적으로 생성되었습니다.");
        } catch(Exception e){
            System.out.println(e.getMessage() + "다시 입력해 주시기 바랍니다.");
        }
    }
    static File createFile(String fileName) throws Exception{
        if(fileName == null || fileName.equals("")){
            throw new Exception("파일 이름이 유효하지 않습니다.");
        }
        File f = new File(fileName); // File 클래스의 객체를 만든다.
        f.createNewFile(); // createNewFile 메서드를 이용해서 실제 파일을 생성한다.
        return f; // 생성된 객체의 참조를 반환한다.
    }
}

예외 되던지기 (re-throwing)

예외를 처리한 후에 다시 예외를 생성하여 호출한 메서드로 전달하는 것을 말하며 예외가 발생한 메서드와 호출한 메서드 양쪽에서 예외를 처리해야 하는 경우 사용된다.

public class ExceptionTest{
    public static void main(String[] args){
        try{
            method1(); // method1 메서드에서 예외가 전달된다 5
        } catch(Exception e){ // 예외처리 6
            System.out.println("main 메서드에서 예외처리 되었습니다.");
        }
    }
    static void method1() throws Exception{ 4
        try{
            throw new Exception(); // 고의로 예외 발생 1
        } catch(Exception e){ // 예외처리 2
            System.out.println("method1 메서드에서 예외처리 되었스니다.");
            throw e; // 다시 예외를 발생 시킨다. 3
        }
    }
}

// 결과
// method1 메서드에서 예외처리 되었습니다.
// main 메서드에서 예외처리 되었습니다.

사용자 정의 예외 만들기

기존의 예외 클래스를 상속받아서 새로운 예외 클래스를 정의할 수 있다.

class MyException extends Exception{
    private final int ERR_CODE; // 상수
    
    MyException(String msg, int errCode){ // 생성자
        super(msg);
        ERR_CODE = errCode; // 생성자를 통해 상수 초기화
    }
    MyException(String msg){
        this(msg, 100); // MyException(String msg, int errCode) 생성자 호출
        // ERR_CODE는 기본값으로 100으로 초기화 된다.
    }
    
    public int getErrCode(){
        return ERR_CODE;
    }
}
Comments