자바 스터디 9주차 : 예외 처리

hwanse·2021년 2월 17일
0

Java

목록 보기
10/14

이 글은 백기선님의 라이브 스터디 참여 및 학습 내용에 관한 정리한 글입니다.





학습 목표

  1. 자바에서 예외 처리 방법(try, catch, throw, throws, finally)
  2. 자바가 제공하는 예외 계층 구조
  3. Exception과 Error의 차이
  4. RuntimeException과 이외 것의 차이
  5. 커스텀한 예외 만드는 방법




예외 처리 (try, catch, finally)

자바에서 프로그램이 실행되는 도중에 발생하는 예외 사항들에 대한 처리를 위해서 try,catch,finally문을 사용할 수 있다.

  • try 블록: 기본적으로 먼저 실행되는 코드로 이 블럭 안에서 발생한 예외는 해당 Exception과 일치한 catch 블록에서 처리된다.
  • catch 블록: try 블록에서 발생한 예외 코드나 예외 객체를 인수로 전달받아 그 처리를 담당한다.
  • finally 블록: try 블록에서의 예외 발생 여부는 상관없이 맨 마지막인 finally 블럭 안에 기술된 코드가 무조건 실행된다.

catch 블록과 finally 블록은 선택적인 옵션으로 반드시 사용할 필요는 없으며, 사용할 수 있는 적합한 모든 try 구문은 다음과 같다. (다른 제어문들과는 달리 예외 처리문은 중괄호({})를 생략할 수 없다)

  1. try / catch
  2. try / finally
  3. try / catch / .. / finally

문법 예시

try {
  // 예외가 발생할 여지가 있는 코드를 이 블럭안에 기술한다
} catch (Exception e1) {
  // e1 예외가 발생할 경우 실행될 코드
} catch (Exception e2) {
  // e2 예외가 발생할 경우 실행될 코드
} finally {
  // 예외 발생 여부 상관없이 무조건 실행되는 코드
}

예외처리 실행 순서


-이미지 참조 : http://www.tcpschool.com/lectures/img_java_exception_intro.png

위 그림에서 try, finally 블록 구문들은 무조건 수행될 코드들이며 try 블럭 안에서 실행중 예외가 발생하게 된다면 그 예외를 받는 catch 구문으로 자동으로 넘어가 처리될 것이다.
정리하자면 크게 다음과 같은 순서로 진행되는 것이다.
try 블럭 실행 -> (예외발생시) catch 블럭 실행 -> finally 블럭 실행

주의점

이외에도 주의할 사항은 참조 변수 중복이 선언 불가하다는 것이다. 참조 변수 중복 선언이 안된다는 것은 try-catch 문 안에 또 try-catch 구문이 있을때 혼동될 수 있을 것같다. 이는 try-catch구문 안에서도 변수의 스코프가 적용되기 때문이며 중복 선언을 하려하는 경우 컴파일 에러가 발생하게 된다 다음은 억지로 만들어낸 예시이며 가볍게 보자.

public class Main {
  public static void main(String[] args) {
    int a = 0;

    try {
      // int a = 1; 컴파일 에러
      int b = 1 / 0;  // ArithmeticException 발생!

      try {
        //int b = 0; 컴파일 에러
      } catch(Exception e) {
      
      }

    } catch(ArithmeticException e) {
      int c = 0;

      try {
        //int a = 1;  컴파일 에러
        int b = 1; // b는 try 블럭 안에서 선언된 지역변수이므로 
                   // catch 블럭 안에서는 변수의 Scope이 다르다.
        //int c = 1;  컴파일 에러
      } catch(Exception e1) {	// catch문 매개 변수 네이밍 또한 중복 불가

      }

    }
  }
}

간단히 정리하자면, try/catch 각 구문별 블럭을 기준으로 변수의 스코프를 생각하면 될 것 같다.

예외 발생시키기(throw)

자바에서는 throw 키워드를 사용하여 강제로 예외를 발생시키는 것이 가능하다

try {
  throw new Exception(); // throw 키워드를 통해 Exception을 강제로 발생시켰다.
} catch(Exception e) {
  //예외 핸들링
}

예외 회피하기(throws)

위 사용된 throw키워드랑 비슷하지만 사용되는 의미는 다르다. throws 키워드는 메소드 선언부에서 사용되며 해당 메소드 블럭 내에서 발생할 수 있는 예외를 미리 명시하는 것이 가능하다. 이를 통해 메소드 내에서 try-catch 구문으로 감싸 핸들링을 하지 않아도 되며 일종의 메소드 내부에서 예외 처리에 대한 책임을 회피하는 것으로 보면된다. 메소드를 사용할 때 발생할 예외 사항을 이 메소드 사용자에게 인지 시키는 것이 가능하며, 예외 처리를 강제할 수 있다.

class B {
  static void run() throws Exception() {
    throw new Exception(); // 강제로 예외를 발생시키고 throws를 통해 예외 회피
  }
}
public class Main {
  public static void main(String[] args) {
    
    try {
      B.run();
    } catch(Exception e) {
      // 예외 처리..
    }
    
  }
}

try-with-resources문

Java SE 7 부터 사용한 자원을 자동으로 해제해 주는 try-with-resource 문을 사용할 수 있다.
문법
try(파일을 열거나 자원을 할당하는 명령문) { }
try 블록에 괄호를 추가해 파일을 열거나 자원을 할당하는 명령문을 명시했을 경우, 해당 try 블록이 끝나자마자 자동으로 파일을 닫거나 할당된 자원을 해제해 준다.

class TestFile {

  // java 7 아래 버전에서
  static String readFile1(String filePath) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(filePath));
    
    try {
      return br.readLine();
    } finally {
      if (br != null) br.close();
    }
    
  }
  
  // java 7 부터
  static String readFile(String filePath) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
      return br.readLine();
    }
    
  }
}


자바가 제공하는 예외 계층 구조

자바에서 프로그램 실행 중 발생할 수 있는 오류는 Exception, Error 가 있으며, 이 두가지를 클래스로 추상화했다. 예외와 에러는 각각 다음과 같은 계층 구조를 가지고 있다.

- 이미지 참조 : https://madplay.github.io/img/post/2019-03-02-java-checked-unchecked-exceptions-1.png

Exception과 Error는 Throwable 클래스를 상속받고 있으며 Throwable은 Object를 상속 받고 있는 것을 볼 수 있다.

Exception과 Error의 차이

  • Exception(예외) : 입력 값에 대한 잘못된 처리, 잘못 참조된 값과 같은 프로그램 실행중 흐름을 어긋나는 것을 말한다. 자바에서는 이러한 예외는 개발자가 직접 처리가 가능하여 예외 상황에 대해서 미리 예측하여 프로그램이 흐름을 어긋나지 않도록 예외 처리 코딩을 통해 핸들링이 가능하다.
  • Error(오류) : 시스템 레벨에서 프로그램에 심각한 문제를 야기하여 실행중인 프로그램이 강제적으로 종료된다. 이러한 오류는 개발자가 미리 예측 처리할 수 없는 것들이 대부분이라 처리할 무언가 대응할 수 있는 부분이 없다.

RuntimeException과 이외 것의 차이

Exception 클래스를 상속받는 여러 Exception들 중에서 RuntimeException을 제외한 나머지는 Checked Exception이라고 표현하며, RuntimeException은 Uncheked Exception이라고도 표현한다.

Checked Exception

컴파일 시점에서 확인할 수 있는 예외다. 개발자가 코딩을 하던 중 코드 내에서 CheckedException을 발생하게 된다면 반드시 해당 예외에 대한 핸들링을 해주어야 한다.
아래와 같은 코드 처럼 예외 처리를 안해주면 컴파일을 할 수 없다.

try {
  throw new IOException(); // 예외를 던진다
} catch(Exception e) {
  // 예외 핸들링..
}

Unchecked Exception

주로 개발자의 실수에 의해서 발생하게 되며 대표적으로 배열에서 범위를 벗어난 index로 접근할 때 발생하는 IndexOutOfBoundException이나, Null 인 값을 참조해서 멤버 변수를 호출하면서 발생하는 NullPointerException과 같은 것들이 대표적이라고 볼 수 있다. 이 Unchecked Exception 항목들은 별다른 예외 처리 없이 컴파일 시 문제가 되진 않으나 이 또한 예외가 발생하지 않도록 개발자가 주의하여 코딩하는 것이 중요하다.

class Main {
  public static void main(String[] args) {
    throw new RuntimeException(); // 이와 같이 RuntimeException을 던져도 컴파일상 문제 없다
  }
}

Checked vs Unchecked 비교

Checked ExceptionUnchecked Exception
클래스Exception 클래스의 자손들 중
RuntimeException을 제외한 모든 클래스
Runtime Exception 클래스와 그 자손 클래스
처리여부반드시 예외 처리가 필요명시적으로 처리를 강제하지 않음
확인시점컴파일 단계실행 단계
대표적인 예외- IOException
- SqlException
- NullPointerException
- IllegalArgumentException
- IndexOutOfBoundException
- SystemException


커스텀한 예외 만드는 방법

자바에서는 Exception 클래스를 상속받아 개발자가 자신만의 새로운 예외 클래스를 정의하고 사용이 가능하다. 커스텀 예외 클래스는 생성자뿐만 아니라 필드, 메소드도 원하는 만큼 추가가 가능하다.

class MyException extends RuntimeException {
  public MyException(String errorMessage) {
    super(errorMessage);
  }
}



참고

profile
만사가 귀찮은 ISFP가 쓰는 학습 블로그

0개의 댓글