티스토리 뷰

언어/자바

예외처리

uijin-j 2023. 6. 25. 12:36

에러(error)를 번역하면 오류인데, 책에서 에러와 오류를 다른 의미로 씀^^.

책에서 개념적인 오류와 자바 클래스 오류(Error)를 모두 한국어 에러로 쓰고 있기 때문인 듯, 자바 예외 클래스의 ExceptionError를 의미할 경우 그냥 영단어를 쓰겠음. 그리고 개념적으로(예외 클래스X) 오류/에러를 사용할 경우, 같은 말이므로 그냥 오류를 쓰지 않고 모두 '에러'로 쓰겠음.

 

✔️ 예외처리?

: 프로그램의 정상적인 흐름을 유지할 수 있도록, 예외(런타임 에러)를 처리하는 메커니즘

(참고) 예외(Exception)은 모두 런타임 에러지만, 런타임 에러가 모두 예외(Exception)은 아님!

 

🙋🏻‍♀️ JVM은 예외처리를 어떻게 할까?

(1) 메서드에서 예외(exception)이 발생하면, 메서드가 예외 객체(인스턴스)를 생성해서 JVM에게 전달!

(2) 해당 예외를 발생시킨 메서드에서 예외 처리 코드(try-catch)(= Exception Handler)를 찾고, 예외 처리 코드가 없는 경우 예외 객체를 호출 스택의 하위 메서드로 예외 전파

(3) 호출 스택의 모든 메서드가 예외를 처리할 수 없는 경우(catch 블록이 없는 경우) JVM의 Uncaught Exception Handler(기본 예외 처리기)를 사용하여 예외를 처리

(4) Uncaught Exception Handler는 예외 객체에 대한 정보를 출력하고 프로그램을 비정상적으로 종료

 

✔️ 에러?

: 프로그램의 정상적인 흐름을 방해하는 원하지 않거나 예상치 못한 이벤트

 

1️⃣ 런타임 에러

: 프로그램 실행 시(런타임)에서 발생하는 에러

 

2️⃣  컴파일 에러는?

: 컴파일 시에 발생하는 에러

: 대부분 문법적 오류로 발생 (ex. 세미콜론(;) 누락, 선언되지 않은 변수 사용, ClassNotFoundException, IllegalAccessException, NoSuchMethodException 등)

: 따라서 컴파일 에러는 예외처리의 대상이 아님! (컴파일 에러는 프로그램 실행파일(.class)을 만드는 과정에서 발생하므로 이미 컴파일이 잘 끝나서 class파일이 만들어지면 런타임 중에는 컴파일 에러가 날 일이 없음!)

 

3️⃣ 논리적 에러

: 프로그램이 실행은 되지만, 의도와 다르게 동작하는 것

 

 

❗ 자바에서는 에러를 Exception과 Error로 구분!

✔️ Error

: 발생하면 복구할 수 없는 심각한 (런타임) 에러, 개발자가 예외처리를 할 수 있는 것이 아님!(프로그램이 비정상적으로 종료)

(ex) OutOfMemoryError(메모리 부족), StackOverflowError(스택오버플로우)

: JVM 메모리 부족, 메모리 누수, 스택오버플로우, 라이브러리 비호환성, 무한 재귀 등으로 발생! (런타임 환경 자체와 관련된 오류)

 

✔️ Exception

:  에러가 발생하더라도 개발자가 예외처리를 통해 프로그램의 비정상적 종료를 막을 수 있는 에러

: 사용자의 실수(잘못된 사용자 입력, 사용할 수 없는 파일 열기), 외적인 요인(장치 오류, 네트워크 연결 끊김, 물리적 제한), 개발자의 실수(코드 오류)로 발생!

 

1️⃣ Checked Exception 

: 컴파일 시에 예외처리를 확인하는 예외

(ex. IOException, ClassNotFoundException)

: 메서드에서 Checked Exception을 throw 하는 경우 메서드는 (1)예외를 처리하거나 (2)throws 키워드를 사용하여 예외를 명시(위임)해야 함!

void method() throws Exception { ... }

 

2️⃣ Unchecked Exception

: 컴파일 시에 예외처리를 확인하지 않는 예외 (컴파일러가 예외처리를 강제X)

(ex. ArithmeticException, NullPointerException, IndexOutOfBoundsException, ClassCastException)

: 따지고 본다면 Error로 Unchecked Exception임!

 

✔️ try-catch / try-catch-finally 문으로 예외 처리

try {
    // 예외가 발생할 가능성이 있는 코드 블록
} catch (Exception e) {
    // 예외 발생 시, 이를 처리하기 위한 코드 블록(예외 핸들러)
} finally {
    // 예외 발생 여부에 관계없이 항상 수행되어야 코드 블록
}

case1) 예외O + 예외처리O

: 예외가 발생한 이후의 try 블록 실행X → 해당 예외를 catch하는 catch 블록 수행 → finally 블록 수행(있는 경우) → 예외처리문(try-catch(-finally)) 이후의 문장 수행

case2) 예외O + 예외처리X

: 예외가 발생한 이후의 try 블록이 실행X → 해당 예외를 catch하는 catch 블록이 없다면, finally 블록 수행(있는 경우) → 메서드 종료 후 예외를 호출 스택의 하위 메서드로 전파!

case3) 예외X

: catch 블록 수행X → finally 블록 수행(있는 경우) → 예외처리문이후의 문장 수행

 

❕ try블럭 또는 catch블럭에 return문이 있더라도 finally 블럭을 수행한 뒤에 메서드를 종료

 

✔️ 여러 개의 예외 가능성이 있는 경우

 try {
    // ArithmeticException과 ArrayIndexOutOfBoundsException을 throw할 가능성이 있는 코드블록
}
catch (ArithmeticException e) { ... }
catch (ArrayIndexOutOfBoundsException e) { ... }

: catch 블럭을 여러개 사용

 

try { ... }
catch (Exception e) {
    if (e instanceof ArithmeticException)
        // ...
    if (e instanceof ArrayIndexOutOfBoundsException)
        // ...
}

: 다형성 이용

 

try { ... }
catch(ArithmeticException | ArrayIndexOutOfBoundsException e) { ... }

: 멀티 catch

❕ '|'로 연결된 예외 클래스가 상속관계면 컴파일 에러

 

✔️ 메세드에 예외를 선언해서 예외처리(throws)

void method() throws Exception { ... }

❕ throws되는 예외는 무조건 checked exception! (unchecked exception은 의미가 없음..)

❕ 사실 Exception을 throws하는 것은 좋은 관례가 아님! 메서드 선언부에 예외를 선언하는 것은 메서드 사용자가 메서드의 선언부만 보고도 어떤 예외들이 처리되어야 하는지 쉽게 알수있도록 하기 위해서이기 때문!

❕ 따라서, 메서드를 사용하는 쪽(호출하는 쪽)에서 예외를 처리하기 때문에 메서드 내에서 예외를 처리할 필요가 없음! (예외처리 위임)

 

🙋🏻‍♀️ 두가지 예외처리를 모두 하고 싶다면?

💡 throw로 예외를 되던지기!

void method() throws Exception {
    try { ... }
    catch (Exception e){
        // 메서드 내 예외처리
        throw e;
    }
}

 

✔️ 사용자정의 예외 만들기

: 보통 Exception 클래스 또는 RuntimeException 클래스를 상속해서 구현!

: Exception 클래스를 상속하면 checked eception을 만드는 것(예외처리 필수O)

: RuntimeException 클래스를 상속하면 unchecked eception을 만드는 것(예외처리 필수X)

class MyException extends Exception {
    public MyException(String str) {
        super(str);
    }
}

 

 

🙋🏻‍♀️ 사용자 정의 예외, 왜 쓰는거지?

https://tecoble.techcourse.co.kr/post/2020-08-17-custom-exception/

 

custom exception을 언제 써야 할까?

우아한테크코스의 두 크루인 오렌지와 우가 싸우고 있다. 왜 싸우고 있는지 알아보러 가볼까? 오렌지 : 아니 굳이 사용자 정의 예외 안 써도 됩니다!! 우 : 아닙니다!! 써야 합니다!!! 사용자 정의

tecoble.techcourse.co.kr

 

🙋🏻‍♀️ checked exception을 unchecked exception으로 바꾸고 싶어!

💡 checked exception을 unchecked exception의 원인 예외로 등록하기!

if(!enoughSpace())
    throw new RuntimeException(new MemoryException("메모리가 부족합니다."));
if(!enoughSpace()) {
    RuntimeException e = new RuntimeException("런타임 에러 발생");
    e.initCause(new MemoryException("메모리가 부족합니다."))
    throw e;
}

+) 이렇게 하면 여러가지 예외를 하나의 큰 분류의 예외로 다룰 수 있음!

 

✔️ try-catch-resources문을 이용한 자동 리소스 관리

: 원래는 try-catch-finally로 리소스 반환을 했음 (try-catch문을 너무 많이 사용하고 코드가 복잡)

: 하나 이상의 리소스를 선언하는 try문에서 사용!

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    String str = br.readLine();
} catch(IOException e) { ... }
BufferedReader br = new BufferedReader(new FileReader(file));
try (br) {
    String str = br.readLine();
} catch(IOException e) { ... }

: 따로 finally문장에서 br.close()를 호출하지 않아도 try 블럭을 벗어나는 순간 자동적으로 close가 호출!

❗ 이때, 리소스(ex. BufferedReader)는 AutoCloseable 인터페이스를 구현하고 있어야 함!

🙋🏻‍♀️ 만약 try문에서 예외가 발생했는데, 리소스를 close()하는 과정에서 예외가 발생한다면?

💡 두 예외가 동시에 발생할 수 없음! try문에서 발생한 예외를 기본으로 하고, CloseException은 억제된(suppressed) 예외로 다룸! try문에서 발생한 예외가 억제된 예외의 정보를 가지고 있음!

 

✔️ 예외 정보를 출력하는 방법

1️⃣ printStackTrace() - 예외이름: 예외설명, 호출스택에 있던 메서드 정보 출력

2️⃣ toString() - 예외이름: 예외설명

3️⃣ getMessage() - 예외설명

❕ Throwable의 메서드 이므로 Throwable을 상속하고 있는 모든 클래스에서 사용가능

 

 

'언어 > 자바' 카테고리의 다른 글

컬렉션 프레임웍  (0) 2023.07.13
java.lang패키지와 유용한 클래스  (0) 2023.06.29
객체지향 프로그래밍Ⅱ  (1) 2023.06.15
객체지향 프로그래밍Ⅰ- 2  (0) 2023.04.27
객체지향 프로그래밍Ⅰ- 1  (0) 2023.04.27
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함