회고록 블로그

[공부 필기] Java 기본 공부하기 (22) 본문

2. 프로그래밍 언어 공부/Java

[공부 필기] Java 기본 공부하기 (22)

김간장 2021. 11. 30. 20:34

공부 중인 강의 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의.

링크 : https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com


1. 예외 클래스 직접 정의하기

- 필요에 따라 프로그래머가 직접 예외 클래스를 정의할 때도 있음

- 프로그램을 구현하다보면 "논리적 예외"가 발생할 수도 있음

   → 코드가 잘못된 것은 아님

   → e.g. 사용자에게 주민등록번호를 입력받을 때 뒷자리 첫번째는 1, 2, 3, 4 중의 하나이어야하는데 9가 입력됨 등

- 예외 클래스를 직접 정의하는 방법

   → 1번. Exception 클래스를 상속함

class CheckResidentNumberException extends Exception {
    ....
}

   → 2번. 메시지를 등록하고 싶다면 super 키워드를 이용해서 상위클래스의 생성자를 호출함

        * super의 인자로 문자열을 전달하면 Throwable 생성자에 의해 detailMessage에 값이 대입됨 ([그림1] 참고)

class CheckResidentNumberException extends Exception {
    public CheckResidentNumberException() {
        super("유효하지 않은 주민등록번호");
    }
}

[그림1] Throwable 생성자 (출처: Java API Documentation)

 

2. 직접 정의한 예외 클래스를 "예외를 처리하는 과정"에 적용하기

- 1을 통해 예외 클래스를 직접 정의하는 것까지는 완료됨

- 이제 "예외를 처리하는 과정"에 우리가 정의한 예외 클래스를 적용해야함

   → 간단하게 정리하자면,

   → 1) JVM이 프로그램의 코드를 읽으면서 '프로그래머가 정의한 예외 상황'이 있는지 찾을 수 있도록 해야하고

   → 2) 만약 해당 예외가 존재하면 실행을 멈추고

   → 3) '프로그래머가 정의한 예외 인스턴스'를 생성토록 해야하고

   → 4) 그 다음 try ~ catch문이 있는지 확인하는 과정이 있어야함

 

 

- 적용한 예시

   → 코드 설명

/* CheckResidentNumberException 클래스
 * 위에서 언급한 '예외처리 과정'에서 3)에 해당하는 인스턴스가 될 클래스이다.
 * 사용자로부터 유효하지 않은 주민등록번호가 입력되면 생성되도록 구성할 예정.
 */
class CheckResidentNumberException extends Exception {
	public CheckResidentNumberException() {
		super("유효하지 않은 주민등록번호");
	}
}
/* ReadResidentNumber 클래스
 * 우선 사용자로부터 값(주민등록번호)을 입력 받아 변수에 저장하며
 * 주민등록번호 뒷자리의 왼쪽 첫번째 숫자(변수 firstDigit)를 체크해서 1~4 이외의 숫자가 있으면 예외를 발생시킨다.
 * 그 예외는 ReadResidentNumber를 호출한 메인 메소드에서 try~catch문으로 처리할 예정.
 */

import java.util.Scanner;

public class ReadResidentNumber {
	int frontNumber;
	int backNumber;
	
	public ReadResidentNumber() {
		Scanner sc = new Scanner(System.in);
		frontNumber = sc.nextInt(); // 주민등록번호 앞자리
		backNumber = sc.nextInt(); // 주민등록번호 뒷자리
	}
	
	public int checkResidentNumberFirstDigit() throws CheckResidentNumberException {
		
		Scanner sc = new Scanner(System.in);
		int firstDigit = backNumber / 1000000; // 뒷자리 첫번째 숫자만 추출
		
		switch(firstDigit) {
		case 1:
		case 2:
		case 3:
		case 4:
			break;
		default:
			throw new CheckResidentNumberException(); // 예외 발생
		}
		return firstDigit;
	}
}
/* Main 클래스 (메인메소드가 있는 메소드이다)
 * ReadResidentNumber에서 발생한 예외를 try ~ catch문으로 처리하는 역할을 할 예정.
 */
public class Main {
	public static void main(String[] args) {
		ReadResidentNumber person = new ReadResidentNumber();
		
		try {
			int digit = person.checkResidentNumberFirstDigit();
			System.out.println("주민등록번호 뒷자리 첫번째 숫자는 "+digit+" 입니다.");
		}
		catch(CheckResidentNumberException e) {
			e.printStackTrace();
		}
	}
}

 

- 방법(정리)

   → ReadResidentNumber 클래스의 아래 코드는 예외를 발생시키는 역할을 함 (= throw 키워드)

        * 예외를 발생시킨 덕분에 JVM은 실행을 잠시 멈추고 예외를 처리하기 위한 매커니즘을 구동하기 시작함

   → 그리고 예외 클래스(CheckResidentNumberException)를 생성(= new 키워드) 해주었음

        * 보통 JVM이 자동으로 예외 인스턴스를 생성해주지만, 여기에서는 프로그래머가 직접 인스턴스를 생성해줘야함

        * 그렇기 때문에 new 키워드를 이용해서 인스턴스를 생성해줌

...
throw new CheckResidentNumberException(); // 예외 발생
...

   → 이후는 다른 Exception을 상속하는 클래스들과 동일함

         * 예외를 처리하기 위해 1) try ~ catch문을 찾거나 2) throws로 예외 처리의 책임을 던져야함

         * 예시의 코드에서는 throws 키워드로 예외 처리의 책임을 '호출한 곳'으로 던졌음 (아래 코드 참고)

...
public int checkResidentNumberFirstDigit() throws CheckResidentNumberException {
...

   → 해당 메소드를 호출한 곳(=예시에서는 메인메소드)으로 가보니 try ~ catch문이 있고,

         catch문의 인자로 CheckResidentNumberException 인스턴스를 전달할 수 있어서 예외 처리를 함 (아래 코드 참고)

...
try {
    int digit = person.checkResidentNumberFirstDigit();
    System.out.println("주민등록번호 뒷자리 첫번째 숫자는 "+digit+" 입니다.");
}
catch(CheckResidentNumberException e) {
    e.printStackTrace();
...

    → 예외를 다 처리한 후에는 try문 밖에 있는 코드부터 다시 하나씩 실행함

 

3. 다중 catch문 주의하기

- 아래와 같이 구성한 경우

   → 상속관계가 아래와 같이 되어있는 Exception 클래스들

   → 이때, CException 예외가 발생하면 3개의 catch문 중에서 어느 catch문이 실행될까

        * 정답은 catch(AException e)문이 실행됨

   → 그 이유는 상속의 특성 때문임

         * catch(AException e)의 참조변수 e는 AException e = new CException(); 과 동일한 코드임

         * CException e = new AException();은 불가능하지만, AException e = new CException();은 가능함

   → 위와 같이 구성하면 두번째와 세번째 catch문은 한번도 실행되지가 않음

   → 따라서 상속의 특성에 의해서 순서를 변경해야함

 

 

Comments