예외 클래스의 계층 구조
자바에서는 실행 시 발생할 수 있는 오류 (Excepton과 Error)를 클래스로 정의하였다.
모든 클래스의 조상인 Object 클래스가 최상단에 있고 Exception과 Error 클래스의 자손이 있다,
모든 예외의 최고 조상은 Exception 클래스이며 Exception 은 Checked Exception과 Uncheked Exception으로 나눌 수 있다.
Error
대부분의 에러는 프로그램 밖에서 발생하고 메모리 부족과 같은 복구 불가능한 경우이다.
Error는 프로세스에 영향을 주어 프로그램이 멈춰 버릴 수 있고 비정상적인 종료를 막을 수 없다.
Excepton
대부분의 Exception 들은 프로그램 내에서 발생하고 복구 가능하다.
예외가 발생하더라고 프로그래머가 적절한 코드를 미리 작성해 놓으면 프로그램의 비정상적인 종류를 막을 수 있다.
스레드에만 영향을 주어 프로그램을 계속 실행할 수 있다.
Exception의 종류
- Chekced Exception
- Unchekced Exception
Chekced Exception
checked Exception 은 컴파일 시 컴파일러가 check 해주는 Exception이다.
컴파일러는 프로그래머가 핸들링할 수 있는 Excepton 인지 아닌지 판단해 준다.
프로그래머는 checked exception를 처리해야만 한다. 처리하지 않으면 컴파일에러가 발생한다.
Uncheked Exception
unchekd Exception 은 chekd Exception과 반대이다.
컴파일러가 컴파일 시점에 exception를 판단해 주지 않고 프로그램 실행 시 즉 런타임시 발생하는 에러입니다.
uncheked exception를 runtime exception 이라고도 한다.
때문에 프로그래머가 예외를 던지거나 처리하지 않아도 프로그램은 컴파일 에러를 발생시키지 않는다.
일반적으로 사용자가 프로그램과 사용작용하는 동안 잘못된 데이터를 제공하는 경우 발생한다.
JVM 은 예외를 어떻게 처리하나요?
기본 예외 처리: 메서드 내부에서 예외가 발생하면 메서드는 예외 객체를 생성하여 런타임 시스템(JVM)에 넘깁니다.
예외 객체는 예외 이름과 설명, 에러가 발생한 현재 프로그램 상황들을 포함합니다.
예외 객체를 생성하고 런타임시스템에서 처리하는 것을 예외 발생이라 합니다.
예외가 발생한 메서드에 도달하기 위해 호출된 메서드 목록이 있을 수 있는데 이 메서드 목록을 호출 스택이라 한다.
자바 예외의 콜스택이 언제 수집될까?
예외의 콜 스택은 예외 객체가 생성되는 시점에 수집이 된다.
일반적으로 Java 의 예외 객체는 Throwable 클래스의 서브 클래스 (Exception이나 Error)로, 객체가 생성될 때 현재 스택 트레이스가 기록됩니다. 이 과정에서
Throwble 클래스의 생성자에서 수행되며 , 이 시점 콜스택을 캡처하여 예외가 발생하는 위치와 호출된 메서드의 순서를 저장하게 됩니다.
런타임 시스템은 발생할 예외를 처리할 수 있는 코드 블록(예외 처리기하고 함)을 포함하는 메서드를 찾기 위해 호출 스택을 검색한다.
런타임 시스템은 예외가 발생한 메서드부터 검색을 시작하고 메서드가 호출된 순서의 역순으로 호출 스택을 검색한다.
적절한 핸들러를 찾으면 발생한 예외를 핸들러에게 전달한다.
1. 예외 발생: 예외가 발생하면 JVM 은 예외 객체를 생성하고, 예외를 발생시킨 메서드의 호출 스택을 추적한다.
2. 예외 객체 전파: JVM 은 해당 예외를 발생시킨 메서드에서 예외 처리 코드를 찾는다, 예외 처리코드가 없는 경우에는 예외 객체를 호출하여 스택의 상위 메서드로 전파시킨다,
3. 예외 처리: 예외 객체가 상위 메서드로 전파되게 된다면, 해당 예외를 처리할 수 있는 catch 블록을 찾고 없다면 다시 상위로 전파된다.
4. 예외 처리 실패 : 예외 객체가 최상위 메서드까지 전파되어도, 예외를 처리할 수 있는 catch 블록이 없는 경우 JVM 은
예외를 처리하지 못한 것으로 판단하여 해당 예외를 처리할 수 있는 DefaultExceptonHandlder를 사용해 예외를 처리한다
5. DefaultExceptonHandlder 실행 : DefaultExceptonHandlder는
예외가 발생한 메서드에서 바로 처리가 된다면 가장 좋지만, 바로 처리되지 못한다면 JVM 은 해당 예외를 처리할 수 있는 메서드를 찾을 때까지 계속해서 상위 메서드로 거슬러 올라가면서 메모리의 호출 스택을 탐색하게 된다.
Exception 이 비싼 연산이라는 말 중에 콜스택을 수집하는 것도 하나의 원인이 된다.
콜스택이란?
메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출되면 콜스택에 호출된 메서드를 위한 메모리가 할당되며, 이 메모리를 메서드가 작업을 수행하는 동안 지역변수들과 연산의 중간 결과 등을 저장하는 데 사용된다. 그리고 메서드가 작업을 마치면 할당되었던 메모리 공간은 반환되어 비워진다.
각 메서드를 위한 메모리상의 작업공간은 서로 구별되면, 첫 번째로 호출된 메서드를 위한 작업공간이 호출스택 맨 밑에 마련되고 , 첫 번째 메서드 수행 중에 다른 메서드를 호출하면, 첫 번째 메서드의 바로 위에 두 번째 호출된 메서드를 위한 공간이 마련된다.
첫 번째 메서드는 수행을 멈추고, 두 번째 메서드가 수행되기 시작한다. 두 번째로 호출된 메서드가 수행을 마치게 되면, 두 번째 메서 들어 위해 제공되었던 호출 스택의 메모리 공간이 반환되며, 첫 번째 메서드는 다시 수행을 계속하게 된다.
호출 스택의 제일 상위에 위치하는 메서드가 현재 실행 중인 메서드이며, 나머지는 다 대기상태에 있게 된다.
따라서 호출스택을 조사해 보면 메서드 간의 호출관계와 현재 수행 중인 메서드가 어느 것인지 알 수 있다.
콜스택 특징
- 메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다.
- 메서드가 수행을 마치고 나며 사용했던 메모리를 반환하고 스택에서 제거된다.
- 호출 스택이 제일 위에 있는 메서드가 현재 실행 중인 메서드이다.
- 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다.
반환 타입 (return type) 이 있는 메서드는 종료되면서 결괏값을 자신을 호출한 caller(호출한 메서드)에서 반환한다. 대기 상태에 있던 호출한 메서드 caller는 넘겨받은 반환값으로 수행을 계속한다.
이팩티브 자바
복구 가능한 상황이면 Checked Excepton 사용하라
- 호출하는 쪽에서 복구하리라 여겨지는 상황이라면 checked Exception를 사용하라
- checked Exception 은 검사 예외를 던지면 호출자가 그 예외를 catch로 잡아 처리하거나 더 바깥으로 전파하도록 강제하게 된다.
복구 불가능한 경우면 unchecked Exception를 사용하라
- 프로그래밍 오류를 나타낼 때는 런타임 예외를 사용하자
- 프로그램에서 해당 에러를 던졌다는 것을 복구가 불가능하거나 더 실행해 봐야 득보다는 실이 많다는 뜻이다.
- 이런 Throwable을 잡지 않은 스레드는 적절한 오류 메시지를 내뱉으면 중단된다.
- 배열 index에 -1과 같은 세팅할 경우 해당 API의 명세에 기록된 제약을 지키지 못한 경우를 말한다.
Cheked Exception 은 실수다?
cheked Exception 이 나쁜 이유
특정 메서드에서 cheked exception을 throw 하고 상위 메소드에서 그 exception 을 catch 한다면, 모든
중간 단계 메소드에서 exception 을 throws 해야 한다.
이는 개방 폐쇄 원칙위배이다. 상위 메서드에서 하위 메서드의 디테일에 대해 알아야 하기 때문이다.
cheked Exception를 사용하면 예외 처리 블록을 반드시 명시해주어야 하기 때문에 에러를 제어하는데 적절할 것이라고 생각했다.
하지만 실제로 하위 블록에서 예외를 던지는 경우 상위 블록에서 try catch로 묶어야 하면 실제로 에러 로그만 기록하고 작업을 주로 했다.
복구할 수 있는 에러나 따로 에러발생 시 작업이 필요한 경우는 유용하겠지만 그렇지 않으면 가독성만 해칠 것 같다.
참고자료
https://medium.com/@rushilakade66/hierarchy-of-java-exception-classes-eb90c5112a02
https://www.geeksforgeeks.org/exceptions-in-java/https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Throwable.html
https://www.javaguides.net/2024/06/java-throwable-fillinstacktrace-method.html
'JAVA' 카테고리의 다른 글
[자바의 신2] 정리해봅시다 [2장~ 11장] (0) | 2024.11.07 |
---|---|
[JAVA] Grabage Collection Basics (0) | 2024.11.05 |
[JAVA] staic 과 final (1) | 2024.10.29 |
== 와 equals 차이 , hashcode (0) | 2024.10.24 |
[Java] Call by Value 와 Call by Reference (6) | 2024.10.21 |