목차
- 예외(exception)
- 예외 클래스 계층 구조
- 예외처리 방법
3-1. throws
3-2. try-catch
3-3. finally - 사용자 정의 예외클래스
1. 예외(exception)
- 프로그램 실행 중 문제가 발생해 구동에 영향 받는 것을 크게 오류와 예외로 구분할 수 있다.
- 오류(error)란 시스템상에서 프로그램에 심각한 문제가 발생해 실행 중이던 프로그램이 종료되는 것을 가리킨다.
❗ 에러(error)는 물리적 오류를 말하므로 프로그램 작성하는 개발자가 미리 예측하거나 처리하는 등 직접 다룰 수 있는 영역이 아니다.
- 예외(Exception)는 미리 예측하고 처리할 수 있을 만큼 상대적으로 미약한 오류를 말한다. 그렇지 못할 경우 오류와 마찬가지로 비정상적인 종료가 치러진다.
❗ 개발자는 이러한 예외에 대하여 예외 상황을 적절히 처리(==예외처리)하고, 코드의 흐름을 컨트롤할 수 있어야 한다.
2. 예외 클래스 계층 구조
- Exception과 Error 클래스 모두 Throwable 클래스의 자손이다.
- Exception은 예외 클래스 중 최상위 클래스이다.
Throwable
△
| 상속
Exception | Error
△
| 상속
IOExeption | RuntimeException
△
| 상속
FileNotFoundException | NullPointerException | IndexOutOfBoundsExeption
- RuntimeException은 실행 시 발생할 수 있는 익셉션으로, Unchecked Exception이다.
- RuntimeException 후손 클래스로는 다음과 같은 것들이 있다.
ArithmeticException : 0으로 나누는 경우 발생. if문으로 나누는 수가 0인지 유효성 검사 실시한다.
NullPointerException : null 값인 참조변수로 객체 멤버 시도 시 발생. 사용 전 참조변수가 null인지 유효성 검사 실시한다.
NegativeArraySizeException : 배열 크기가 음수인 경우 발생. 배열의 크기를 0보다 크게 지정한다.
ArrayIndexOutOfBoundsException : 배열 index 범위를 넘어서서 참조하는 경우 발생. 배열명.length를 사용해 범위 확인 후 쓴다.
ClassCaseException : Cast 연산자 사용 중 타입 오류 해당 시 발생. instanceof 연산자로 객체 타입 확인 후 연산에 사용한다.
- 작성 중 빨간 줄로 명시 또는 예외처리 강제 대상이 아니기 때문에, null 값이 들어있는지 유효성 검사를 실시한 다음 조건을 실행하는 등 코드 개선이 답이다.
- 반면 IOException은 입출력 관련 익셉션으로, Checked Exception에 해당한다.
- 앞서 컬렉션 프레임워크에서 Map 계열 인터페이스의 Properties를 다룰 때 try-catch를 불러오며 봤을 것이다.
- Checked Exception은 반드시 체크해 예외처리가 우선되어야 하는 익셉션이다. 컴파일 에러에 해당한다.
3. 예외처리 방법
3-1. throws로 위임한다.
- 자신을 호출한 상위 메소드에게 익셉션 처리를 위임한다. 즉 위임을 통해 예외 처리를 강제화할뿐 실질적인 해결 방안은 되지 못한다.
- throws 사용 목적은 원하는 위치에서 try-catch하기 위함이다.
public void checkEnoughMoney(int price, int money) throws Exception {
System.out.println("가지고 계신 돈은 " + money + "원 입니다.");
if(money >= price) {
System.out.println("상품을 구입하기 위한 금액이 충분합니다.");
} else {
throw new Exception();
}
System.out.println("즐거운 쇼핑하세요~");
}
public static void main(String[] args) throws Exception {
ExceptionTest et = new ExceptionTest();
et.checkEnoughMoney(10000, 50000); //정상 동작et.checkEnoughMoney(50000, 10000); //비정상적 종료System.out.println("프로그램을 종료합니다."); //출력되지 못함
- 만약 상위 메소드에서도 연이어 throws를 던지고 있다면, 즉 끝끝내 main 메소드에서까지 throws를 던진다면, 비정상 종료돼 콘솔 창에서 익셉션 오류 코드를 확인할 수 있을 것이다. 익셉션에 대해 해결되지 않은 상황을 말한다.
- 비정상 종료된다 함은 최하단의 구문, 즉 예외발생 구문 이하부터는 동작하지 않고 되돌아온다는 뜻이다.
3-2. try-catch로 처리한다.
- try 블럭 안에 예외 발생 가능성이 있는 메소드를 호출한다.
- 이때 호출 구문에서 예외가 발생했다고 읽히면, try 블럭 안의 하단 코드는 더 이상 동작하지 않는다.
- 해당 메소드 호출 시 예외가 발생하거든 곧장 catch 블럭의 코드가 실행되기 때문이다.
catch(Exception e)
ExceptionTest et = new ExceptionTest();
try {et.checkEnoughMoney(-50000, 50000);주석et.checkEnoughMoney(50000, -50000);주석
et.checkEnoughMoney(30000, 50000);
} catch(Exception e) {
e.printStackTrace();
}
❗ e.printStackTrace();
어디서 에러가 났는지 빨간색 글씨로 에러 로그를 출력해준다. 예외 클래스명, 예외 발생 위치, 예외 메시지 등을 stack 호출 역순에 따라 로그 형태로 출력해주는 기능을 수행한다.
- 위 예시에서는 try 블럭에 작성한 메소드 호출 구문들을 하나씩 주석하며 사용해야 한다.
- 최상단의 것을 가장 먼저 읽어가기 때문에, 주석하지 않으면 이전 결과가 계속 출력되는 등 의도하지 않은 결과를 낼 수 있다.
3-3. finally
try {
...
} catch (...) {
...
} finally {
System.out.println("프로그램을 종료합니다.");
}
- 예외 발생 여부와 상관 없이 실행할 내용을 담는다.
4. 사용자 정의 예외클래스
- Exception 클래스를 상속 받아 작성한다: extends Exception
- FileNotFoundException, NullPointerException와 같은 익셉션을 직접 만들어 볼 수 있는 것이다.
- 사용자 정의 예외클래스에서 선언할 것은 두 가지이다: A. 기본 생성자, B. 문자열을 부모 생성자 쪽으로 전달하며 초기화하는 생성자
public NotEnoughMoneyException() {}
- A. 기본 생성자
public NotEnoughMoneyException(String message) {
super(message);
}
- B. 문자열을 부모 생성자 쪽으로 전달하며 초기화하는 생성자
- 익셉션 발생 시 메시지를 초기화하는 용도이다. 부모 생성자로부터 인스턴스를 생성 받을 수 있도록 전달할 것이다.
예외 상황별 catch 블럭
ExceptionTest et = new ExceptionTest();
try {
et.checkEnoughMoney(-30000, 50000);
} catch (PriceNegativeException e) {
System.out.println("PriceNegativeException 발생!");
System.out.println(e.getMessage());
} catch (MoneyNegativeException e) {
System.out.println("MoneyNegativeException 발생!");
System.out.println(e.getMessage());
} catch (NotEnoughMoneyException e) {
System.out.println("NotEnoughMoneyException 발생!");
System.out.println(e.getMessage());
} finally {
System.out.println("finally 블럭의 내용이 동작함");
}
System.out.println("프로그램을 종료합니다.");
- 예외 상황별로 catch 블럭을 따로 작성해서 처리할 수 있다.
- 예외 인스턴스 생성 시 전달한 메시지를 getMesssage()로 가져올 수 있다. 이때 반환되는 것은 Throwable.class String getMessage() 메소드의 detailMessage이다.
multi-catch
- JDK 1.7버전에서 추가된 구문으로, 동일한 레벨이자 타입이 다른 예외를 하나의 catch 블럭으로 다룰 수 있다.
try {
et.checkEnoughMoney(20000, 10000);} catch(Exception e) {System.out.println("모든 종류의 Exception 발생!");
} catch (PriceNegativeException | MoneyNegativeException | NotEnoughMoneyException e) {
e.printStackTrace();
System.out.println(e.getClass() + " 발생!");
System.out.println(e.getMessage());
} catch(Exception e) {
System.out.println("모든 종류의 Exception 발생!");
} finally {
System.out.println("finally 블럭의 내용이 동작함");
}
System.out.println("프로그램을 종료합니다.");
- catch 블럭을 나열하는 경우 각 Exception의 상속 관계를 고려해서 나열해야 한다.
- catch(Exception e)가 보다 상위에 있어 매번 먼저 동작되거든 그 밑으로 따르는 상황별 catch 블럭은 동작할 일이 없게 된다. Exception은 모든 Exception 타입의 부모이기 때문이다.
- 상황별 catch 블럭을 먼저 작성한 뒤 그 밑으로 catch(Exception e) 블럭을 둔다면, 상황 외의 다른 익셉션들을 이곳에서 받아 처리해 줄 수 있을 것이다.
'Java' 카테고리의 다른 글
[JAVA] 13-2. 예외처리 | finally | try-with-resource | 오버라이딩 (0) | 2022.01.12 |
---|---|
[JAVA/수업 과제 practice] ArrayList 데이터 관리 프로그램 만들기 (0) | 2022.01.12 |
[JAVA] 12-2. 컬렉션 | Map | HashMap | Properties (0) | 2022.01.11 |
[자바의 정석] Ch 11. 컬렉션 프레임워크 강의 메모 (0) | 2022.01.11 |
[자바의 정석] Ch 6. OOP I 예제 응용 학습 (0) | 2022.01.10 |