본문 바로가기
JAVA

3. 예외와 예외처리

by seongju.lee 2022. 12. 15.

에러와 예외

자바에서 에러(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