에러와 예외
자바에서 에러(Error)와 예외(Exception)은 분명한 차이를 가지는 용어이다.
- 에러(Error)는 코드로 수정할 수 없는 심각한 오류를 뜻한다.
- 예외(Exception)는 코드로 수정할 수 있는 미약한 오류를 뜻한다.
즉, 예외는 프로그래머가 코드를 적절하게 작성해주면 방지할 수 있는 영역인 것이다.
예외클래스의 계층구조
- 예외나 에러와 관련된 최상위 클래스인 Throwable로부터 상속받은 구조이다.
- Error는 시스템 레벨에서 발생하는 것이다.
- Exception 클래스들은 외적인 요인으로 인해 발생하는 것들이 대부분이다. (e.g. 파일없음, 프로그래머 실수)
- 여기서 중요한 점은 RuntimeException인데 해당 예외는 프로그래머의 실수로 발생하는 예외라고 할 수 있다.
그렇다면, 프로그래머가 처리할 수 있는 수준의 Exception은 어떤 식으로 처리하는 지 살펴보자.
try-catch 블럭
자바에서는 예외처리를 할 때, try{}catch(){}블럭을 사용하여 예외 처리를 하게 된다.
try{
.
.
.
}catch(Exception1 e1){
// Exception1이 발생했을 때의 조치
}catch(Exception2 e2){
// Exception2가 발생했을 때의 조치
}
- 위와 같은 방식으로 예외처리를 하게 된다.
- try블럭 내부에서 로직을 수행하던 도중에 Exception1이라는 예외가 발생하면 첫 번째 catch블럭으로 이동하여 조치를 하게 되는 것이다.
- 만약 Exception2라는 예외가 try 블럭 안에서 발생하면 두 번째 catch 블럭으로 이동하게 된다.
- catch블럭을 수행한 후에는 try-catch문을 벗어나서 다음 코드를 실행하게 된다.
멀티 catch블럭
위에서 try-catch문을 세부적으로 작성하게 되면 catch문이 너무 길어지며, 코드의 중복이 발생할 수도 있게된다.
이렇게 내용이 같은 catch블럭을 하나로 합치기 위한 것이 멀티 catch블럭이다.
try{
.
.
.
}catch(Exception1 | Exception2 e){
e.printStackTrace();
}
위 코드와 같이 Exception1과 Exception2의 예외 처리방식이 동일하다면 or연산자를 이용하여 처리가 가능하다.
근데 위 방식에서 주의해야 할 점이 두 가지가 있다.
첫번째, 부모-자식관계는 사용하지 않는다.
당연한 내용이긴 하지만 아래 코드와 같다.
try {...}
catch(ParentException | ChildException){...}
위 코드를 보면 catch 블럭 내부에서 상위 | 하위 클래스끼리 묶어 놓았다.
근데 catch에서 조건을 판단할 때는 instanceof 연산자를 사용하기 때문에 굳이 부모-자식 관계을 해놓을 필요가 없는 것이다.
try {...}
catch(ParentException){...}
위 코드처럼 당연히 상위 클래스만 해놓으면 처리가 가능할 것이다.
두번째, 여러개 묶어놓은 예외 클래스 내부에 동일하게 있는 메소드만 사용 가능하다.
이 내용도 너무 당연한 말이다.
try{...}
catch(Exception1 | Exception2 e){
e.Method1()
}
위 코드처럼 Exception1과 Exception2를 묶어놨지만, Exception1에만 존재하는 메소드를 catch 블럭 내부에서 사용하면 안될 것이다.
그 이유는 e라는 것이 Exception1의 객체라는 보장이 없기 때문이다.
만약 이렇게 사용하고 싶다면 catch문 안에서 e가 어떤 객체인지 확인해줄 필요가 있을 것이다.
try{...}
catch(Exception1 | Exception2 e){
if(e instanceof Exception1){
Exception1 e1 = (Exception1)e;
e1.method1();
}
}
위 코드처럼 Exception1의 객체인지 확인 후, 명시적으로 형변환을 해서 사용해줘야 적용이 가능할 것이다.
예외 발생시키기 - throw
프로그래머가 예상치 못한 내용으로 예외가 발생할 수도 있지만 예외를 생성하고, 발생시킬 수도 있다.
- new 연산자를 이용하여 예외클래스 객체를 생성하고, throw 키워드로 예외를 발생시킨다.
try{
throw new Exception("예외 발생시킴");
}catch(Exception e){
e.printStackTrace();
}
위와 같이 throw로 예외를 발생 시켰기 때문에 당연히 try-catch문으로 예외처리를 해줘야 한다.
근데 사실 모든 예외가 try-catch를 해줘야만 하는 것은 아니다.
해도 되고, 안해도 되고의 구분은 checked예외, unchecked예외 라는 것으로 나눌 수 있는데 구분은 아래와 같다.
checked, unchecked 예외
1. checked예외: 컴파일러가 예외처리 여부를 체크한다 -> 예외 처리가 필수
checked예외는 RuntimeException을 제외한 Exception클래스와 그 하위클래스들이다.
2. unchecked예외: 컴파일러가 예외처리 여부를 체크하지 않는다. -> 예외 처리가 선택
unchecked예외는 RuntimeException과 그 하위클래스들이다.
즉, 위(throw예시)의 예시처럼 Exception을 발생시켰다면 try-catch가 필수로 와줘야만 했지만,
만약 throw new RuntimeException("예외 발생시킴"); 이었다면 try-catch가 선택적으로 와도 되는 것이다.
'JAVA' 카테고리의 다른 글
JVM의 동작 원리와 구조 구체적으로 이해하기 (3) | 2024.02.12 |
---|---|
4. Collections.sort()와 Arrays.sort() (0) | 2023.01.17 |
1. 자바 컴파일 과정 (0) | 2022.11.23 |
22. 인터페이스 (0) | 2022.11.14 |
21. 추상 클래스, 추상 메서드 (0) | 2022.11.11 |