상세 컨텐츠

본문 제목

예외처리 (Exception, RuntimeException, 사용자 정의 예외)

기록 - 프로그래밍/Java

by wjjun 2024. 1. 22. 00:31

본문

 

일반 실행 예외

 

예외란

잘못된 조작 또는 개발자의 코딩으로 발생하는 프로그램 오류입니다.

예외처리를 하는 목적은 예외처리를 통해 프로그램이 종료되지 않고 정상 실행 상태를 유지하는 것입니다.

 

일반예외

컴파일러가 체크하는 예외를 의미합니다. 컴파일 과정에서 예외 처리 코드가 필요한지 검사합니다.

일반예외는 예외 처리 코드가 없으면 컴파일 오류가 발생합니다.

 

실행예외

컴파일 과정에서 예외 처리 코드를 검사하지 않습니다.

 

자바는 예외를 클래스로 관리합니다. 

JVM에서 프로그램을 실행하면서 예외가 발생하면 해당 예외 클래스 객체를 생성합니다.

그리고 예외 처리코드에서 예외 객체를 이용할 수 있습니다. (java.lang.Exception)

 

일반 예외와 실행 예외를 구분하는 방법은 일반 예외는 Exception을 상속받고 RuntimeException은 상속받지 않는 클래스입니다.

실행 예외는 RuntimeException을 상속받는 클래스입니다.

 

JVM에서는 RuntimeException 상속했는지 확인하고 실행 예외를 판단합니다.

 

AnnotationTypeMismatchException,

ArithmeticException, ArrayStoreException, 

BufferOverflow, BufferUnderflow Exception,

CannotRepoException, CannotUndoException, ClassCastException,

CMMException, ConcurrentModification, DataBinding, DateTime, DOM, EmptyStack.. 등등

 

RuntimeException 클래스를 상속받은 예외 클래스인지 JVM에서 확인합니다.

 

 

다중 catch 

프로그램이 갑자기 종료되는 것을 방지하고 정상 실행을 유지하도록 처리해야 합니다.

실행 예외는 컴파일러가 체크해주지 않기 때문에 예외 처리 코드를 개발자가 고민해서 작성해야 합니다.

 

다중 catch 장단점

장점은 각 예외 유형에 대한 정확한 예외처리 동작을 정의할 수 있습니다.

catch 블록마다 예외처리 로직이 구조적으로 분리되어 가독성이 좋습니다

오류 메시지 커스터마이징을 유용하게 제공할 수 있습니다.

 

단점은 비슷한 처리 코드가 중복해서 발생할 수 있습니다.

하위 클래스부터 상위 클래스 순으로 catch 블록을 나열해야 합니다. 상위 클래스의 catch 문이 하위 클래스를 가릴 수 있습니다.

catch 블록이 있다면 오류 처리 코드를 관리하기 어려울 수 있습니다. 서로 다른 예외 유형을 처리하기 때문에 오류 처리 로직을 변경에 있어 부담이 있습니다.

catch 블록을 검색하는 실행 시간이 소요됩니다.

 

 

try-with-resource

자바 7에서 추가된 try-with-resource를 사용하면 예외 발생과 관계없이 사용된 리소스 객체(스트림, 서버소켓, 채널 등)를 close() 하는 메서드를 호출해서 안전하게 리소스를 닫아줍니다.

 

리소스란 데이터를 읽고 쓰는 객체를 의미합니다.

 

try - catch - finally를 사용하면 아무래도 마지막에 close() 메서드를 항상 선언해야 하는 불편함이 있습니다.

try - with - resource를 사용하면 아래와 같이 명시적으로 close() 호출 없이도 try 블록이 정상 실행 완료했거나 예외가 발생해도 자동으로 FileOutputStream의 close() 메서드가 호출됩니다.

try(FileInputStream fls = new FileInputStream("file.txt")) {
    ...
} catch(IOException e) {
    ...
}

// 복수 개의 리소스 사용시
try(
    FileInputStream fls = new FileInputStream("file.txt");
    FileOutputStream fos = new FileOutputStream("file.txt")
) {
    ...
} catch(IOException e) {
    ...

try {} 에서 예외가 발생하면 우선 close()로 리소스를 닫고 catch 블록을 실행합니다.

리소스 객체는 java.lang.AutoCloseable 인터페이스를 구현하고 있어야 합니다.

AutoCloseable에 정의되어 있는 close() 메서드를 try-with-resource는 close() 메서드를 자동 호출합니다.

 

AutoCloseable 인터페이스에서 All Known Implementing Classes를 보면 try-with-resources와 함께 사용할 수 있는 리소스가 무엇이 있는지 확인할 수 있습니다.

 

 

예외 넘기기

상황에 따라 메서드를 호출한 곳으로 예외를 넘겨야 하는 경우가 있습니다.

throws가 사용됩니다.

 

public void method1() {
    try {
        method2();
    } catch (ClassNotFoundException e) {
        // 예외처리 코드
        sout("클래스가 존재하짖 않습니다.");
    }
}


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

ClassNotFoundException 예외가 발생하면 method2에서 예외 처리를 하지 않고

method2() 선언된 method1() 에서 예외처리를 진행합니다.

 

 

사용자 정의 예외

예를들어 잔고부족에 대한 예외는 java 클래스로 제공하고 있지 않습니다.

서비스 관련된 예외를 애플리케이션 예외라고 표현합니다.

 

이것은 개발자가 직접 만들며 사용자 정의 예외라고 합니다.

 

사용자 정의 예외 클래스 선언

컴파일러가 체크하는 일반 예외로 선언할 수도 있고, 컴파일러가 체크하지 않는 실행 예외로 선언할 수도 있습니다.

일반 예외는 Exception을 상속하면 되고, 실행 예외는 RuntimeException을 상속하면 됩니다.

public class ExampleException extends [ Exception | RuntimeException ] {
    public Example1Exception() { }
    public Example2Exception(String message) { super(message); } 
}

사용자 정의 예외 클래스도 필드, 생성자, 메서드 선언들을 포함할 수 있으며 대부분 생성자의 선언만 포함합니다.

 

생성자는 두개를 선언하는 것이 일반적입니다.

하나는 매개 변수가 없는 기본 생성자

다른 하나는 예외가 발생한 원인 메시지를 전달하기 위한 String 타입의 매개 변수를 갖는 생성자 입니다.

String 타입의 매개 변수를 갖는 생성자는 상위 클래스의 생성자를 호출하여 예외 메시지를 넘깁니다.

 

 

예외 발생시키기

throw new ExampleExcpetion();
throw new ExampleExcpetion("message");

예외 객체를 생성해서 예외를 발생시키는 방법입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

관련글 더보기

댓글 영역