티스토리 뷰
에러(error)를 번역하면 오류인데, 책에서 에러와 오류를 다른 의미로 씀^^.
책에서 개념적인 오류와 자바 클래스 오류(Error)를 모두 한국어 에러로 쓰고 있기 때문인 듯, 자바 예외 클래스의 Exception과 Error를 의미할 경우 그냥 영단어를 쓰겠음. 그리고 개념적으로(예외 클래스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 |