본문 바로가기
  • 비둘기다
  • 비둘기다
  • 비둘기다
코딩/JAVA Basics

[자바 JAVA] 예외처리

by parzival56 2022. 12. 6.

자바의 오류는 예외와 에러로 나뉩니다.

예외는 자바 프로그램에서 실행 중에 발생할 수 있는 경미한 오류들을 말합니다. 이러한 예외들은 적절한 처리 모듈을 추가하여 발생한 문제를 복구 가능합니다.

에러는 메모리나 내부의 심각한 문제로 복구가 불가능한 오류입니다. 즉, 코드를 다시 수정해야 하는 경우이죠.

 

간혹 가다가 디버깅을 해보게 되면 콘솔 창에 빽빽한 글자로 Exception이라는 글자가 들어가 있는 경우를 보게 됩니다.

이가 바로 예외가 발생한 경우입니다. 예외가 발생하면 바로 프로그램이 중단되므로 발생한 이후의 프로그램을 실행하지 않습니다. 그리고 콘솔 창에 예외 클래스의 이름과 예외가 발생한 프로그램 소스와 줄 번호가 표시됩니다. 

그중 여러분들이 한 번쯤은 보셨을 법한 예외들을 소개해보겠습니다.

 

NullPointerException

          ▪ 실제 변수에 저장된 객체가 null임에도 불구하고 객체의 멤버를 참조하려는 경우 발생

ArrayIndexOutOfBoundsException

          ▪ 배열에서 배열의 첨자 범위를 벗어난 첨자 사용

ArithmeticException

          ▪ 0으로 수를 나누려 할 때 발생

ArrayStoreException

          ▪ 배열에 잘못된 유형의 객체를 저장하려 할 때 발생

ClassCastException

          ▪ 객체를 변환할 수 없는 유형으로 변환하려고 할 때 발생

NegativeArraySizeException

          ▪ 배열의 크기를 음수로 지정하는 경우 발생

 

저는 이들 중 위의 3가지를 많이 본거 같은데 자바에는 이러한 예외들을 핸들링하는 구문들이 존재합니다.

이러한 과정을 예외처리라고 합니다. 

 

예외처리란, 실행 중에 여러 이유로 예상하지 못했던 문제가 발생한 경우 이를 적절히 처리하는 모듈입니다.

예외처리 모듈로는 try - catch - finally문장이 있습니다.

이 모듈에서 finally는 예외 발생과 상관없이 무조건 실행됩니다. catch와 finally 둘 중 하나는 옵션입니다.

둘 중 하나는 빠져도 되지만 둘 다 빠지면 안 되고 둘 다 쓰는 것은 상관없습니다. 

 

try {
	// 예외가 발생할 수 있는 문장들
    ...
} catch (발생가능예외클래스이름 변수이름) {
	// 예외 처리 모듈
} finally {
    // 항상 실행되는 문장들
    // 보통은 여기에 try에 들어가는 문장을 넣음
}

위가 try - catch - finally문이며 catch에 들어가는 발생 가능한 예외 클래스 이름에는 위의 Exception들의 이름들을 넣어도 되고 이들을 모두 통칭할 수 있는 Exception이라는 단어만 넣어도 됩니다.  

만약 try 내부에서 예외가 발생한다면 위의 그림처럼 예외가 발생한 문장 밑 부분은 실행하지 않습니다. 

위에 제가 발생한 예외 클래스란에 구체적인 예외의 이름을 명시해도 되고, Exception만 적어도 된다고 했는데 이는 보통 여러 개의 catch문을 사용할 때 쓰입니다. 여러 개의 catch문을 쓰는 경우에는 컴파일러가 위에서 아래로 순차적으로 코드를 실행합니다. 그래서 예외의 이름을 밑으로 갈수록 포괄적인 범위로 적어야 합니다. 

try {
	~~~~~~
}catch (NullPointerException e) {
	~~~~~~~
}catch (ArithmeticException e) {
	~~~~~~~
}catch (Exception e) {
	~~~~~~
}

위의 코드처럼 catch를 여러 개 사용할 경우에는 Exception을 디폴트 값처럼 사용합니다. 

예외의 계층 구조도

이 예외들은 체크 예외와 비체크 예외로 나뉘는데 비체크 예외로는 위 그림의 RuntimeException과 하위의 예외들인데 이들은 try - catch문 사용이 선택적입니다. 말 그대로 runtime이상이기 때문에 코드 자체의 문제가 아닙니다. 단지 코드가 비효율적이라 이 데이터들을 처리하는 시간이 많이 걸릴 뿐이라 이들은 예외처리가 선택사항이죠. 

그러나 나머지 예외들은 모두 체크 예외이며 비체크 예외에 비해 비교적 무거운 에러들입니다. 

추가적으로 등장한 예외들도 살펴보자면 이렇습니다. 

▪ FileNotFoundException – 존재하지 않는 파일을 처리

▪ ClassNotFoundException – 사용하려는 클래스의 이름을 잘못 기술

▪ DataFormatException – 입력한 데이터의 형식이 잘못

 

예외에 대하여 특이한 클래스, 인터페이스가 있는데 바로 forName(className)입니다.

이는 class 메서드 중에 정적 메서드이며 인자인 className의 객체를 반환하는 메서드입니다. 인자인 className의 클래스가 없다면 ClassNotFoundException 예외를 발생시킵니다. forName(className)을 호출하는 부분에서 반드시 예외처리를 수행해야 하며 아니면 컴파일 에러가 발생합니다. 

public static Class<?> forName(String className) throws ClassNotFoundException

 

체크 예외를 처리하는 방법은 2가지가 있습니다.

1. try - catch구문 사용

2. 예외가 발생할 수 있는 구문이 속한 메서드에서 다시 예외를 전달하고 상위 메서드로 예외처리를 미루는 방법입니다,

 

// 1번
public class TryCheckedException {
    public static void main(String[] args) {

    //메소드 Class.forName()을 사용하려면 반드시 예외처리를 해야 함
    try {
        System.out.println(Class.forName("java.lang.Object"));
    } catch (ClassNotFoundException ex) {
        System.out.println(ex); }
    }
}
// 2번
public class PropagateCheckedException {

    //메소드 선언에서 다시 예외 ClassNotFoundException의 발생을 전달
    public static void main(String[] args) throws ClassNotFoundException {
        //메소드 Class.forName()을 사용하려면 반드시 예외처리를 해야 함
        System.out.println(Class.forName("java.lang.Object"));
    }
}

Exception은 그 자체가 클래스이기 때문에 상속하는 것이 가능합니다. 

이를 활용한 것이 예외 클래스입니다. 예외 클래스는 Exception을 상속받아 이루어지며 생성자에서 super(msg)로 구현합니다. msg에 저장된 문자열은 메서드 getMessage()에 의해 반환됩니다. 

public class MyException extends Exception {
// MyException처럼 이름은 내가 지정할 새로운 예외의 이름
    public MyException(String msg) {
    	super(msg);
    }
}

생성된 예외 클래스는 필요한 경우 throws가 가능합니다.

public static void doException(boolean bool) throws MyException {
    if (bool)
    	// 실제 예외를 발생시키는 부분에서는 throw를 사용합니다.
        throw new MyException("내가 만든 예외");
}

다음은 예제 코드 사진입니다.

이상 자바에서의 예외 처리에 대해 알아봤습니다.

댓글