본문 바로가기
Java

예외처리 (Exception)

by sontaku 2021. 1. 25.

예외처리 (Exception)

프로젝트 개발 혹은 공부 중 발생하는 Exception에 대해 정리해보자.

[ 예외 (Exception) ]

  • 사용자 혹은 개발자의 잘못으로 발생하는 오류, 처리 가능한 에러
  • 에러 발생시 지속적인 서비스 제공하기 위함
  • 종류
    1. 일반 예외 : 컴파일 체크 계열( Class . . . , )
      • java.lang.RuntimeException 외의 모든 예외 클래스
      • 제약 조건 : try ~ catch 블록으로 처리 필수
    2. 실행 예외
      • java.lang.RuntimeException 상속받는 모든 예외 클래스
      • try ~ catch 옵션


1. Exception의 종류

1-1. NullPointerException

String str = null;
System.out.println(str.length()); // Error
  • 접근한 Object가 null 값일 때 발생한다.

1-2. NumberFormatException

String str = "three";
Integer.parseInt(str); // Error
  • 문자열을 숫자형으로 변환 시 발생한다.

1-3. ArrayIndexOutOfBoundsException

int[] intArr = { 1, 2, 3 };
System.out.println(intArr[3]); // Error
  • 범위 밖의 배열 지정 시 발생한다.

1-4. ClassCastException

class A{}
class B extends A{}
class C extends A{}

public class TestException {
    public static void main(String[] args) {
        A a = new B();
        B b = new B();
        C c = (C)a; // Error
    }
}
  • 클래스 형변환 연산을 잘 못 했을 때 발생한다.

1-5. ArithmeticException

int i2 = 10/0; // Error
  • 제로제산 등 산술 예외 시 발생한다.

1-6. . . .(지속적으로 추가하기)


2. 예외처리 방법

java에서는 대표적으로 try ~ catch 문을 통한 예외처리를 한다.

2-1. try ~ catch 기본형

try {
    // Error가 발생할 수 있는 코드 or 블럭
    예외 발생 가능성 존재하는 코드;
} catch (Exception e) {
    // Error 발생시 수행
    예외 처리 코드;
}
  • 기본적으로 try 문을 먼저 실행하며, Error가 발생하지 않으면 catch 문은 실행되지 않는다.
  • try 문에서 Error가 발생하면 해당 라인까지만 try문을 진행하며, catch 문이 실행된다.

2-2. multi-catch

try {
    String str1 = "three";
    Integer.parseInt(str1); // NumberFormatException
    String str2 = null;
    System.out.println(str2.length()); // NullPointerException
} catch (NumberFormatException | NullPointerException e) {
    e.printStackTrace();
    System.out.println(e.getMessage());
    System.out.println("예외 발생 : NumberFormatException");
} catch (Exception e) {
    System.out.println("예외 발생 : NullPointerException");
}
  • 하나의 try 블록에서 여러개의 예외가 발생하는 경우 많은 catch블럭이 필요하다.
  • Exception 하나로 묶어서 처리할 수도 있지만, 불가피한 경우 multi-catch문을 통해 상황별로 나눌 수 있다는 장점이 있다.

2-3. try ~ catch ~ finally

try {
    예외 발생 가능성 존재하는 코드;
} catch(발생 가능성 존재하는 예외 Exception 변수) { 
    예외 처리 코드;
} finally {
    예외 발생 여부와 무관, 무조건 실행되는 블럭
    주로 자원 반환 로직으로 많이 사용됨
        (ex. DB 접속 해제)
}
  • 구조는 try ~ catch 문과 동일하며, 추가적으로 finally 문은 try ~ catch의 결과와 상관없이 마지막에 무조건 실행되는 블럭이다.


3. 개발 상황에 따른 예외 발생 문법

3-1. body{ } 영역에 throw new 생성자명( [...] ); 구현

   try {
       예외 발생 가능성 존재하는 코드;
       throw new Exception;
   } catch(발생 가능성 존재하는 예외 Exception 변수) { 
       예외 처리 코드;
   }
  • 강제로 예외를 발생시킬 때 사용한다.

3-2. 메소드 선언구에 발생 가능성 예외 알림 표기

반환타입 메소드명( [...] ) throws ~Exception[, ~Exception2 ]{ }

   public static void method() throws Exception { // throws 여러개 가능
       Class clazz = Class.forName("java.lang.String2");
   }

   public static void main(String[] args) {
       try {
           method();
       } catch(발생 가능성 존재하는 예외 Exception 변수) { 
           예외 처리 코드;
       }
   }
  • 예외처리를 책임전가 할 때 사용한다.
  • [ 중요 ] main() 메소드에서도 throws 키워드를 사용하여 예외를 떠넘길 수 있지만, main() 메소드에서 throws Exception을 붙이는 것은 좋지 못한 예외 처리 방법이다.
  • main() 메소드에서는 try ~ catch 블록으로 예외를 최종 처리하는 것이 바람직하다.


4. 사용자 정의 예외 클래스 ( Application Exception )

  • 기본 생성자

  • String 매개변수 존재 생성자

  • 사용자 정의 예외 클래스는 컴파일러가 체크하는 일반 예외로 선언할 수 있다.(Exception)
  • 혹은 컴파일러가 체크하지 않는 실행 예외로 선언할 수도 있다. (RuntimeException)
public class MyException extends Exception { // Exception or RuntimeException
    public MyException() {}
    public MyException(String str) {
        super(obj); // super는 반드시 명시적으로 존재해야 한다.
    }
}
  • 사용자 정의 예외 클래스 명명은 일종의 개발자 사이의 규칙으로 Exception으로 끝나야 한다.
  • 생성자는 일반적으로 기본 생성자와 예외 발생 원인 전달을 위한 String 타입 파라미터를 갖는 생성자이다.


5. 예외처리 예제

  • 다음은 XX은행의 통장이다.
public class TestException2 {

    static int balance = 50; // 잔액 -> 기초 잔액 설정
    static int deposit; // 입금액
    static int withdraw; // 출금액

    // 입금 메소드
    static void plus(int deposit) {
        try {
            // 입금액이 0원이상이면 정상거래
            if (deposit >= 0) {
                balance = balance + deposit;
            } else {
                // 입금액이 0원 이하면 Error
                throw new ArithmeticException();
            }
        } catch (ArithmeticException e) {
            System.out.println("비정상적인 금액 입력입니다.");
            System.out.println("입금이 취소되었습니다.");
        } finally {
            System.out.println("거래가 종료되었습니다.");
        }
    }

    // 출금 메소드
    static void minus(int withdraw) {
        try {
            if (withdraw >= 0) {
                if (balance - withdraw >= 0) {
                    balance = balance - withdraw;
                    System.out.println(withdraw + "원이 출금되었습니다.");
                } else {
                    // 출금 후 잔액이 0원 이하면 Error
                    throw new ArithmeticException();
                }
            }
        } catch (ArithmeticException e) {
            System.out.println("비정상적인 금액 입력입니다.");
            System.out.println("출금이 취소되었습니다.");
        } finally {
            System.out.println("거래가 종료되었습니다.");
        }
    }

    public static void main(String[] args) {
        plus(50);
        System.out.println("잔액은 " + balance);

        System.out.println("----------------------------");

        minus(150);
        System.out.println("잔액은 " + balance);
    }
}

출력창

거래가 종료되었습니다.
잔액은 100
----------------------------
비정상적인 금액 입력입니다.
출금이 취소되었습니다.
거래가 종료되었습니다.
잔액은 100

'Java' 카테고리의 다른 글

Iterator in java  (0) 2021.02.01

댓글