[Java] 예외처리(Exception) 란? - 특징과 사용법

2021. 4. 25. 16:07Java

오류의 종류

- 에러 (Error)
  : 에러 발생 시, 프로그램이 비정상 종료 된다.
  : 정상 실행 상태로 돌아갈 수 없다.
- 예외 (Exception)
  : 사용자의 잘못된 조작 또는 개발자의 잘못된 프로그래밍으로 인한 오류
  : 예외 발생 시, 프로그램이 종료되지만 예외처리를 해줄 경우 정상 실행 상태로 되돌릴 수 있다.

=> 예외처리의 목적은 프로그램을 정상 실행 상태로 돌리기 위함

 

 

Exception 의 종류

- 일반 예외 (= Complie Exception 또는 Checked Exception)

  : 컴파일 시점에 예외가 발생함

- 실행 예외 (=RuntimeException 또는 UnChecked Exception)

  : 실행 시점에 예외가 발생함

 

 

[RuntimeException] 자주 발생하는 Exception

- ArrayIndexOutOfBoundsException

- NullPointerException

- NumberFormatException

- ArithmeticException

- ClassCastException

 

 

ArrayIndexOutOfBoundsException

- 자료형에 존재하지 않는 인덱스 값를 불러오려고 할 때 발생

int[] arr = new int[5];
int check = arr[5];

 

NullPointerException

- null 값을 조작하거나, 초기화되지 않은 객체의 변수나 메소드를 접근하려고 할 때 발생

String str = null;
String check = str.toString();

 

NumberFormatException

- 문자를 숫자로 변경 시, 발생

String str1 = "100";
String str2 = "100가";

int num1 = Integer.parseInt(str1);
int num2 = Integer.parseInt(str2);

 

ArithmeticException
- 수학적인 계산의 과정에서 발생

int num = 10/0;

 

ClassCastException

- 객체의 형을 변환할 때 객체 타입 변환이 적절하지 않을때 발생

- Class 뿐만 아니라 Interface 또한 형의 변환 또한 적절하지 않을때 발생한다.

class A {}
class B extends A {}
class C extends A {}

public class Example {

    public static void main(String[] args) {

	// 정상
        A a1 = new B();
        B b1 = (B) a1;    // B 로 다운캐스팅

	// 오류
        A a2 = new B();
        C c1 = (C) a2;      // C 로 다운캐스팅 -> ClassCastException 발생
    }
}

 

 


Exception Handling

- Java 는 RuntimeException 을 처리할 수 있는 구문을 4가지 제공한다.

  1. 예외가 발생한 메서드 안에서 처리 (try-catch-finally)

  2. 예외가 발생한 메서드를 호출한 곳에서 처리 (throws)

  3. 강제로 예외를 발생시켜서 처리 (throw)

  4. 사용자 예외를 생성하여 처리

 

 

1. 예외 처리 코드 (try-catch-finally)

- 예외가 발생하기 전, 예외 처리 코드를 작성하면 프로그램의 종료를 막고 정상 실행을 유지할 수 있다.

- Checked Exception 는 반드시 작성해야한다. (컴파일이 안되므로...)

- UnChecked Exception 는 컴파일러가 체크해주지 않으므로 개발자의 경험으로 작성한다.

- [정상 실행이 되었을 경우]

  : try 블럭은 무조건 실행된다.

  : catch 블럭은 실행되지 않는다. (다중 catch 블럭 가능)

  : finally 블럭은 무조건 실행된다. (Optional)

- [비정상 실행이 되었을 경우]

  : try 블럭은 무조건 실행된다.

  : catch 블럭은 무조건 실행된다.

  : finally 블럭은 무조건 실행된다. (Optional)

 

참고

- 다중 catch 구문 작성 시, 상위 클래스가 위에 있으면 안된다.

// 틀린 코드 -> Exception 의 최고 조상 Exception 이 catch 구문 맨 위에 존재함
try {
            
} catch (Exception e) {
            
} catch (ArrayIndexOutOfBoundsException e) {
            
} finally {
            
}

 

- JDK 1.7부터 하나의 catch 구문에서 | (파이프)를 사용하여 복수 개의 예외를 처리할 수 있다.

try {

} catch (ArrayIndexOutOfBoundsException | NullPointerException e) {

} catch (Exception e) {

}

 

 

2. 예외 던지기 (throws)

- 메서드 선언부 끝에 키워드 throws 를 붙여서 작성한다.

- 키워드가 붙은 메소드에서 예외발생 시, Exception 처리하라고 호출부로 던진다.

- 호출한 곳에서는 예외를 받기 위해 반드시 예외처리 코드가 있어야 한다.

- 아래 코드는 test() 메소드에서 throws 키워드를 사용하였다.

- test() 에서 예외 발생 시, main() 메서드가 처리해줘야 한다.

- 그러므로 main() 메서드에서 try-catch 구문을 작성해주었다.

public class Example {

    public static void main(String[] args) {

        try {
            test();
        } catch (Exception e) {

        }

    }

    public static void test() throws Exception { }
}

 

 

3. 강제로 예외 발생 시키기 (throw)

- 강제로 예외를 발생 시켜 호출한 곳에 Exception 을 던질 수 있다.

- throws 키워드를 이용해 예외를 던지지 않고, 바로 처리하고 싶다면 test() 에서 try-catch 를 사용하자.

public class Example {

    public static void main(String[] args) {

        try {
            test();
        } catch (Exception e) {
	    e.getMessage();
        }

    }

    public static void test() throws Exception { 
        throw new Exception("예외 강제로 발생");
    }
}

 

 

4. 사용자정의 Exception 처리

- 따로 Exception 종류를 상속 받아 커스터마이징 해주어 예외 발생을 의도한다.

- 자바 표준API 에서 제공하지 않는 예외는 직접 프로그래밍 하여 만들어야 한다.

- 순서

  1. 관례적으로 Exception 을 붙여 준다.

  2. 일반 Exception 인지 RuntimeException 인지 선택하여 상속 받는다. (보통 관리 차원에서 Exception 으로 함)

  3. 기본 생성자를 하나 선언하자.

  4. 조상 클래스인 Exception 의 생성자를 반드시 호출하여 호출이유를 적어주자.

class CustomException extends Exception {

    public CustomException() {
    }

    public CustomException(String message) {
        super(message);
    }
}

public class Example {

    public static void main(String[] args) {

        
        try {
            // 3. 예외 받기
            test();
        } catch (CustomException e) {
            // 4. 사용자정의 Exception 처리
            System.out.println(e.getMessage());
        } catch (Exception e) {
            e.getMessage();
        }
    }

    public static void test() throws Exception {
        // 1. 강제로 예외 발생
        throw new CustomException("사용자정의 Exception !!");

        // 2. main() 로 예외 던지기
    }
}

 

 


참고

e.getMessage()

- 예외를 발생시킬 때, 생성자의 매개변수 값으로 사용한 String return 값


e.printStackTrace()

- 예외 발생 코드를 추적하여 로그들을 전부 console 에 출력

- 개발자 전용이며 프로그램 Test 그리고 Debugging 할 때 유용하다.

- 개발 시에 자주 사용하며, 배포 시 주석처리 또는 제거해야하는 코드

 


연습

1. 코드를 보고 이해 해보자.

public class Example {

    public static void main(String[] args) {

        try {
            // 클래스를 찾아 동적으로 인스턴스화
            Class stringClass = Class.forName("java.lang.String");

	    // 위 코드가 에러날 경우, 아래 코드는 실행 되지 않음
            System.out.println("== String 클래스를 찾았습니다.");
            System.out.println("==[클래스명+패키지]: " + stringClass.getName());
            System.out.println("==[클래스명]: " + stringClass.getSimpleName());

        } catch (ClassNotFoundException e) {
            System.out.println("== String 클래스를 찾지 못했습니다.");
        } finally {
            System.out.println("== 프로그램을 종료하였습니다.");
        }

    }
}

 

2. 코드를 보고 이해 해보자.

public class Example {

    public static void main(String[] args) throws Exception {
        throw new NullPointerException("JVM 에게 예외 던지기!");
    }
}