Backend/Java

[Java] Exception

unknownomad 2023. 12. 5. 00:25

https://www.javamadesoeasy.com/2015/05/exception-handling-exception-hierarchy.html

 

 

예외(Exception)

  • 사용자의 잘못된 조작이나 개발자의 코딩 실수로 인해 발생하는 프로그램 오류
  • 예외가 발생되면 프로그램은 곧바로 종료된다는 점에서 에러와 동일하나,
  • 예외는 예외 처리를 통해 프로그램을 종료하지 않고 정상 실행 상태 유지시킬 수 있음

종류

일반 예외(Checked Exception) 실행 예외(Unchecked Exception)
개발자가 반드시 직접 예외 처리해야 함
Exception 클래스 자체는 Checked exception
개발자가 직접 예외 처리하지 않아도 됨
명시적 예외 처리가 강제되지 않기에 Unchecked
Exception 클래스의 자식 클래스 중 RuntimeException 클래스는 Unchecked 

실행 예외(Unchecked Exception)의 종류

  • RuntimeException 의 자식 클래스들 모두 포함, Unchecked Exception
  • try-catch문으로 예외 처리를 직접 하기보다는 예외가 발생하지 않도록 프로그래머가 주의해야

NullPointerException

  • java.lang.NullPointerException
  • 객체 참조가 없는 상태일 때 발생
  • null 값을 갖는 참조 변수로, 객체 접근 연산자인 도트(.)를 사용했을 때 발생
  • 객체가 없는 상태에서 객체를 사용하려 할 때 예외 발생

ArrayIndexOutOfBoundsException 

  • 배열에서 인덱스 범위 초과 시 발생
int[] arr = new int[3];
arr[4] = 5;

NumberFormatException 

  • 매개값인 문자열이 숫자로 변환될 수 있다면 숫자를 정상적으로 리턴
  • 그러나 숫자로 변환할 수 없는 문자열 포함 시, java.lang.NumberFormatException 발생

ClassCastException 

  • 허용되지 않는데 억지로 타입 변환을 시도 시 발생
Animal animal = new Dog();
Dog dog = (Dog) animal; // ok

RemotControl ex1 = new Television();
Television ex2 = (Television) ex1; // ok

Animal animal = new Animal();
Dog dog = (Dog) animal; // ClassCastException 발생

 


예외 처리 방법

try-catch

try {
    // 예외 발생 가능성 있는 코드
}
catch(예외클래스 e) {
    // 예외 처리
}
finally {
    // 무슨 일이 있어도 항상 실행
}

다중 catch 문

  • 다중 catch 블록 작성 시, 상위 예외 클래스가 하위 예외 클래스보다 아래에 위치하게 해야
  • try 에서 예외가 발생 시, catch 가 작성된 순서대로 위에서 아래대로 차례로 검사하는데,
  • 만일 상위 예외 클래스가 더 위에 있었다면 하위 예외 클래스를 실행하지 X
  • 즉, 하위 예외 클래스가 상위 예외 클래스를 상속했기 때문에, 상위 예외 클래스를 잡는 catch 실행됨
try{
    // 예외1 발생 위치
    // 예외2 발생 위치
}
catch(예외1을 잡는 곳) {
}
catch(예외2를 잡는 곳) {
}

멀티 catch 문

  • 자바 7부터 하나의 catch 블록에서 여러 개의 예외 처리 가능해짐
try {
    // 예외 1 발생위치 (혹은 예외 3 발생위치)
    // 예외 2 발생위치
}
catch( 예외 1 | 예외 3  e) { // | 는 or 로 보면 됨. 예외 1 혹은 예외 3 발생 시,
// 해당하는 catch 블록에서 예외 처리
    // 예외 처리
}
catch( 예외 2 e) {
    // 예외 처리
}

예외 떠넘기기

  • 메소드 내부에서 예외가 발생할 수 있는 코드 작성 시, try-catch 블록으로 예외 처리 하는 것이 기본
  • 경우에 따라 메소드를 호출한 곳으로 예외 처리를 떠넘길 수도 있음
  • 이 때 사용하는 키워드가 throws
public void method1() {

    try {
        method2(); // throws 붙은 method2() 는 반드시 try 문 안에서 호출되어야
       // method2() 가 떠넘긴 예외를 아래 catch 문에서 처리
    }
    catch (ClassNotFoundException e1) {
        System.out.println("클래스가 존재하지 않음.");
    }
    ...
}

public void method2() throws ClassNotFoundException {
    Class clazz = Class.forName("java.lang.String22");
}

 

Q. 만약 method1() 도 예외를 떠넘긴다면?

  • method1() 을 main() 에서 호출했다면, main() 에서 try-catch 통해 예외 처리해야 함
  • 그런데 main() 에서도 예외를 떠넘길 수 있음
  • ➡️ 해당 예외는 JVM 이 최종적으로 처리를 하게 되지만, 이는 권장 사항은 아님

사용자 정의 예외와 예외 발생

사용자 정의 예외 클래스

  • 개발자가 직접 정의하여 만드는 예외
  • 일반 예외(Checked Exceptino)나 실행 예외(RuntimeException / Unchecked Exception) 중 하나로 만듦
  • 일반 예외는 Exception 상속 / 실행 예외는 RuntimeException 상속

Java7 부터의 try-with-resources

  • Java7부터 자원을 자동으로 반납해주는 try-with-resources 문법 추가됨
  • Java는 AutoCloseable 인터페이스를 구현하는 자원에 대해 try-with-resources 를 적용 가능하게 함
  • 이로써 코드가 유연해지고, 누락되는 에러없이 모든 에러를 잡을 수 있게 됨
public static void main(String args[]) throws IOException {

    try(
        FileInputStream is = new FileInputStream("file.txt");
        BufferedInputStream bis = new BufferedInputStream(is)
    ) {
        int data;
        while((data = bis.read()) != -1) {
            System.out.print((char) data);
        }
    }
}

 

Closeable과 AutoCloseable의 관계

  • 기존 Closeable 에 부모 인터페이스로 AutoCloesable 추가함
  • 즉, Cloesable에 부모 인터페이스인 AutoCloesable 을 새로 추가
  • 먼저 만들어진 Cloesable 인터페이스에 부모 인터페이스인 AutoCloesable 추가
  • ➡️ 하위 호환성 100% 달성 + 변경 작업에 대한 수고 덞
  • 만약 Cloesable을 부모로 만들었다면 기존에 만든 클래스들이 모두 Cloesable이 아닌 AutoCloesable를 구현(implements) 하도록 수정해야 했을 것
  • 덕분에 기존 구현된 자원 클래스들 모두 try-with-resources 사용 가능해짐
public interface Closeable extends AutoCloseable {
    public void close() throws IOException;
}

public interface AutoCloseable {
    void close() throws Exception;   
}

 

try-catch-finally 가 아닌, try-with-resources 사용해야만 하는 이유

  • 코드 간결화
  • 번거로운 자원 반납 작업해줄 필요 X
  • 실수로 자원을 반납하지 못하는 경우 방지
  • 에러로 자원을 반납하지 못하는 경우 방지
  • 모든 에러에 대한 스택 트레이스 남길 수 있음

출처

https://www.javamadesoeasy.com/2015/05/exception-handling-exception-hierarchy.html

https://chanhuiseok.github.io/posts/java-3/

https://mangkyu.tistory.com/217