Backend/Java
[Java] Exception
unknownomad
2023. 12. 5. 00:25
예외(Exception)
- 사용자의 잘못된 조작이나 개발자의 코딩 실수로 인해 발생하는 프로그램 오류
- 예외가 발생되면 프로그램은 곧바로 종료된다는 점에서 에러와 동일하나,
- 예외는 예외 처리를 통해 프로그램을 종료하지 않고 정상 실행 상태 유지시킬 수 있음
종류
일반 예외(Checked Exception) | 실행 예외(Unchecked Exception) |
개발자가 반드시 직접 예외 처리해야 함 Exception 클래스 자체는 Checked exception |
개발자가 직접 예외 처리하지 않아도 됨 명시적 예외 처리가 강제되지 않기에 Unchecked Exception 클래스의 자식 클래스 중 RuntimeException 클래스는 Unchecked |
실행 예외(Unchecked Exception)의 종류
- RuntimeException 의 자식 클래스들 모두 포함, Unchecked Exception
- try-catch문으로 예외 처리를 직접 하기보다는 예외가 발생하지 않도록 프로그래머가 주의해야
NullPointerException
- java.lang.NullPointerException
- 객체 참조가 없는 상태일 때 발생
- null 값을 갖는 참조 변수로, 객체 접근 연산자인 도트(.)를 사용했을 때 발생
- 객체가 없는 상태에서 객체를 사용하려 할 때 예외 발생
ArrayIndexOutOfBoundsException
- 배열에서 인덱스 범위 초과 시 발생
int[] arr = new int[3];
arr[4] = 5;
NumberFormatException
- 매개값인 문자열이 숫자로 변환될 수 있다면 숫자를 정상적으로 리턴
- 그러나 숫자로 변환할 수 없는 문자열 포함 시, java.lang.NumberFormatException 발생
ClassCastException
- 허용되지 않는데 억지로 타입 변환을 시도 시 발생
Animal animal = new Dog();
Dog dog = (Dog) animal; // ok
RemotControl ex1 = new Television();
Television ex2 = (Television) ex1; // ok
Animal animal = new Animal();
Dog dog = (Dog) animal; // ClassCastException 발생
예외 처리 방법
try-catch
try {
// 예외 발생 가능성 있는 코드
}
catch(예외클래스 e) {
// 예외 처리
}
finally {
// 무슨 일이 있어도 항상 실행
}
다중 catch 문
- 다중 catch 블록 작성 시, 상위 예외 클래스가 하위 예외 클래스보다 아래에 위치하게 해야
- try 에서 예외가 발생 시, catch 가 작성된 순서대로 위에서 아래대로 차례로 검사하는데,
- 만일 상위 예외 클래스가 더 위에 있었다면 하위 예외 클래스를 실행하지 X
- 즉, 하위 예외 클래스가 상위 예외 클래스를 상속했기 때문에, 상위 예외 클래스를 잡는 catch 실행됨
try{
// 예외1 발생 위치
// 예외2 발생 위치
}
catch(예외1을 잡는 곳) {
}
catch(예외2를 잡는 곳) {
}
멀티 catch 문
- 자바 7부터 하나의 catch 블록에서 여러 개의 예외 처리 가능해짐
try {
// 예외 1 발생위치 (혹은 예외 3 발생위치)
// 예외 2 발생위치
}
catch( 예외 1 | 예외 3 e) { // | 는 or 로 보면 됨. 예외 1 혹은 예외 3 발생 시,
// 해당하는 catch 블록에서 예외 처리
// 예외 처리
}
catch( 예외 2 e) {
// 예외 처리
}
예외 떠넘기기
- 메소드 내부에서 예외가 발생할 수 있는 코드 작성 시, try-catch 블록으로 예외 처리 하는 것이 기본
- 경우에 따라 메소드를 호출한 곳으로 예외 처리를 떠넘길 수도 있음
- 이 때 사용하는 키워드가 throws
public void method1() {
try {
method2(); // throws 붙은 method2() 는 반드시 try 문 안에서 호출되어야
// method2() 가 떠넘긴 예외를 아래 catch 문에서 처리
}
catch (ClassNotFoundException e1) {
System.out.println("클래스가 존재하지 않음.");
}
...
}
public void method2() throws ClassNotFoundException {
Class clazz = Class.forName("java.lang.String22");
}
Q. 만약 method1() 도 예외를 떠넘긴다면?
- method1() 을 main() 에서 호출했다면, main() 에서 try-catch 통해 예외 처리해야 함
- 그런데 main() 에서도 예외를 떠넘길 수 있음
- ➡️ 해당 예외는 JVM 이 최종적으로 처리를 하게 되지만, 이는 권장 사항은 아님
사용자 정의 예외와 예외 발생
사용자 정의 예외 클래스
- 개발자가 직접 정의하여 만드는 예외
- 일반 예외(Checked Exceptino)나 실행 예외(RuntimeException / Unchecked Exception) 중 하나로 만듦
- 일반 예외는 Exception 상속 / 실행 예외는 RuntimeException 상속
Java7 부터의 try-with-resources
- Java7부터 자원을 자동으로 반납해주는 try-with-resources 문법 추가됨
- Java는 AutoCloseable 인터페이스를 구현하는 자원에 대해 try-with-resources 를 적용 가능하게 함
- 이로써 코드가 유연해지고, 누락되는 에러없이 모든 에러를 잡을 수 있게 됨
public static void main(String args[]) throws IOException {
try(
FileInputStream is = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(is)
) {
int data;
while((data = bis.read()) != -1) {
System.out.print((char) data);
}
}
}
Closeable과 AutoCloseable의 관계
- 기존 Closeable 에 부모 인터페이스로 AutoCloesable 추가함
- 즉, Cloesable에 부모 인터페이스인 AutoCloesable 을 새로 추가

- 먼저 만들어진 Cloesable 인터페이스에 부모 인터페이스인 AutoCloesable 추가
- ➡️ 하위 호환성 100% 달성 + 변경 작업에 대한 수고 덞
- 만약 Cloesable을 부모로 만들었다면 기존에 만든 클래스들이 모두 Cloesable이 아닌 AutoCloesable를 구현(implements) 하도록 수정해야 했을 것
- 덕분에 기존 구현된 자원 클래스들 모두 try-with-resources 사용 가능해짐
public interface Closeable extends AutoCloseable {
public void close() throws IOException;
}
public interface AutoCloseable {
void close() throws Exception;
}
try-catch-finally 가 아닌, try-with-resources 사용해야만 하는 이유
- 코드 간결화
- 번거로운 자원 반납 작업해줄 필요 X
- 실수로 자원을 반납하지 못하는 경우 방지
- 에러로 자원을 반납하지 못하는 경우 방지
- 모든 에러에 대한 스택 트레이스 남길 수 있음
출처
https://www.javamadesoeasy.com/2015/05/exception-handling-exception-hierarchy.html