지난 계산기 과제에서 Exception을 상속하여 예외 처리를 하던 중 코드가 지저분해지는 문제가 발생했다. 매번 try-catch 문을 사용해야 했고, 그로 인해 코드가 길어지며 가독성도 떨어졌다. 그래서 RuntimeException으로 변경하여 try-catch 문을 생략하게 되었다.
왜 RuntimeException으로 변경하면 try-catch 문을 생략할 수 있었을까?
Exception을 상속받으면 해당 예외는 CheckedException이 된다. CheckedException은 컴파일러가 예외 처리를 강제하기 때문에, 메서드 내에서 반드시 try-catch로 처리하거나 메서드 선언부에 throws를 붙여야 한다. 그렇지 않으면 컴파일 오류가 발생한다.
하지만 RuntimeException을 상속받은 예외는 UncheckedException이 된다. UncheckedException은 컴파일러가 예외 처리를 강제하지 않기 때문에 try-catch 문을 생략할 수 있다. 즉, 예외를 선택적으로 처리할 수 있어 코드가 훨씬 간결해지고, 불필요한 예외 처리를 줄일 수 있다.
이처럼 RuntimeException을 사용하면 예외를 강제적으로 처리할 필요가 없고, 발생한 예외는 자연스럽게 프로그램 흐름에서 처리되거나, 필요한 경우에만 직접 처리하면 된다. 이로 인해 코드가 더 간결하고 가독성 있게 작성될 수 있었다.
Exception Class
위 사진은 Java의 Exception Class이다.
Exception vs Error
Exception에 대해 본격적으로 알아보기 전에, 자바에서 Exception과 Error의 차이점부터 정리해보려고 한다.
Exception
- 사용자의 잘못된 입력이나 프로그램 코드의 오류로 인해 발생하는 예외 상황을 말한다.
- 이런 예외들은 대부분 프로그램이 실행 중에 발생하고, 개발자가 이를 처리하도록 설계할 수 있다.
- 예를 들어, 계산기 프로그램에서 숫자를 입력해야 할 곳에 문자 'ㅁ'을 입력할 경우 Exception 처리를 해야 한다.
- 대표적인 예로는 NullPointerException, IllegalArgumentException 등이 있다.
Error
- Error는 시스템 자체의 문제로 인해 발생하는 심각한 오류를 의미한다.
- 이런 오류는 개발자가 미리 예측하거나 처리하기 어렵고, 대부분 프로그램이 중단될 수밖에 없다.
- 예를 들어, StackOverflowError, OutOfMemoryError 같은 것들이 여기에 해당한다.
Exception의 종류
자바에서는 예외를 크게 CheckedException과 UnCheckedException으로 나눌 수 있다.
CheckedException
- CheckedException은 컴파일 단계에서 체크되는 예외이다. 즉, 컴파일러가 예외 처리를 강제하는 예외라고 볼 수 있다.
- 이런 예외들은 프로그램이 정상적으로 작동할 수 있는지에 대한 중요한 확인이 필요할 때 발생한다.
- 예를 들어, 파일을 읽거나 네트워크 통신을 할 때 파일이 없거나 네트워크 연결이 끊길 가능성이 있다고 가정하자. 그래서 이런 상황을 대비해 IOException 같은 예외를 처리해야 한다.
- CheckedException은 Exception 클래스를 상속받지만, RuntimeException의 하위 클래스는 아니다.
- 따라서 반드시 try-catch로 처리하거나, 메서드 시그니처에 throws로 선언해야 한다.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class FileExample {
public void readFile(String filePath) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
try {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // 파일의 각 줄을 출력
}
} finally {
reader.close(); // 파일을 다 읽으면 리소스 해제
}
}
public static void main(String[] args) {
FileExample fileExample = new FileExample();
try {
fileExample.readFile("example.txt"); // 읽으려는 파일 경로
} catch (IOException e) {
System.out.println("파일을 읽는 중 오류가 발생했습니다: " + e.getMessage());
}
}
}
UnCheckedException (RuntimeException)
- 반면에, UnCheckedException은 프로그램의 논리적인 오류나 잘못된 입력에서 발생하는 예외이다.
- RuntimeException을 상속받은 예외들이 여기에 속한다.
- NullPointerException, ArrayIndexOutOfBoundsException 같은 예외들이 그 예이다.
- 이 예외들은 컴파일러가 체크하지 않기 때문에 예외 처리를 강제하지 않는다. 그래서 try-catch로 감싸지 않더라도 프로그램이 컴파일은 된다.
package level3.exception;
public class DivisionByZeroException extends AppException {
// 나눗셈 계산을 할때 두 번째 숫자가 0이면 예외가 발생하는 로직
public DivisionByZeroException() {
super("0으로 나눌 수 없습니다.");
}
}
package level3.exception;
public class AppException extends RuntimeException {
// RuntimeException을 상속받는 커스텀 예외 선언
public AppException(final String message) {
super("[ERROR] " + message);
}
}
위 코드는 AppException을 상속받고 있는데, AppException은 RuntimeException을 상속받고 있다. 만약 Exception을 상속받았다면 try-catch문을 사용해야 한다.
결론 RuntimeException을 사용한 이유
사용자가 잘못된 입력('ㅁ' 같은 문자 입력)을 했을 때 발생하는 오류는 논리적 오류나 예측 가능한 상황이다. 그래서 이런 경우는 RuntimeException으로 처리해도 괜찮다. 그 이유를 좀 더 구체적으로 설명해 보겠다.
사용자의 입력 오류는 개발자가 예측할 수 있는 예외 상황
사용자가 잘못된 데이터를 입력하는 상황은 프로그램을 개발하면서 충분히 예상할 수 있다. 예를 들어, 숫자를 입력해야 할 곳에 문자를 입력하면 예외가 발생할 가능성을 쉽게 알 수 있다. 이런 예외는 RuntimeException으로 간주해도 될 거 같다.
- NullPointerException이나 ArrayIndexOutOfBoundsException처럼, 입력 오류도 정상적인 프로그램 흐름 중에 발생할 수 있는 오류이기 때문에 RuntimeException으로 처리해도 문제가 없다.
- 사용자가 잘못된 입력을 했을 때 그 입력을 어떻게 처리할지는 개발자의 선택에 달려 있다. 이 예외를 반드시 try-catch로 감싸야할 정도로 시스템에 치명적인 오류가 아니기 때문에, RuntimeException으로 처리하는 게 더 자연스럽다.
'JAVA' 카테고리의 다른 글
읽기 쉬운 코드 만들기 with 세션 (2 / 2) (3) | 2024.10.01 |
---|---|
읽기 쉬운 코드 만들기 with 세션 (1 / 2) (0) | 2024.09.30 |
캡슐화에 대한 정리 with 세션 (0) | 2024.09.26 |
JVM 동작 방식 (0) | 2024.09.20 |
ArrayList는 어떻게 크기가 조절될까? (0) | 2024.09.11 |
Garbage Collection(GC) 더 자세히 살펴보기 (0) | 2024.09.09 |
Java final과 불변성 (0) | 2024.09.08 |
가비지 컬렉션이란? (1) | 2024.09.06 |