본문 바로가기
개념

[JAVA의 정석] Chapter08_연습문제

by cook_code 2024. 12. 13.

 

[8-1] 예외처리의 정의와 목적에 대해서 설명하시오.

 

정의 : 프로그램 실행 중에 발생할 수 있는 예외적인 상황(오류)을 처리하는 방법

목적 :

  1. 프로그램의 비정상 종료 방지
  2. 오류 원인 파악 및 디버깅 용이
  3. 정확한 오류 처리 및 복구

 

참고

예외 : 프로그램이 정상적으로 실행되는 것을 방해하는 예상치 못한 사건이나 오류


[8-2] 다음은 실행 도중 예외가 발생하여 화면에 출력된 내용이다. 이에 대한 설명 중 옳지 않은 것은?

 java.lang.ArithmeticException : / by zero
 at ExceptionEx18.method2(ExceptionEx18.java:12)
 at ExceptionEx18.method1(ExceptionEx18.java:8)
 at ExceptionEx18.main(ExceptionEx18.java:4)
 

위의 내용으로 예외가 발생했을 당시 호출스택에 존재했던 메서드를 알 수 있다.

예외가 발생한 위치는 method2 메서드이며, ExceptionEx18.java 파일의 12번째 줄이다.

발생한 예외는 ArithmeticException이며, 0으로 나눠어서 예외가 발생했다.

method2메서드가 method1메서드를 호출하였고 그 위치는 ExceptionEx18.java파일의 8번째 줄이다.

 

4

 

풀이 : 에러로 확인 가능한 메서드 호출순서

ExceptionEx18.main(ExceptionEx18.java:4)
  ↓
ExceptionEx18.method1(ExceptionEx18.java:8)
  ↓
ExceptionEx18.method2(ExceptionEx18.java:12)
 

[8-3] 다음 중 오버라이딩이 잘못된 것은? (모두 고르시오)

 void add(int a, int b)
 throws InvalidNumberException, NotANumberException {}

 class NumberException extends Exception {}
 class InvalidNumberException extends NumberException {}
 class NotANumberException extends NumberException {}
 

a.void add(int a, int b) throws InvalidNumberException, NotANumberException {}

b. void add(int a, int b) throws InvalidNumberException {}

c. void add(int a, int b) throws NotANumberException {}

d. void add(int a, int b) throws Exception {}

e. void add(int a, int b) throws NumberException {}

 

d,e

 

풀이

d. void add(int a, int b) throws Exception {}
상위 클래스 메서드와 동일한 시그니처를 가지고 있지만, 더 상위 클래스 예외를 던짐 (Exception은 NumberException의 상위 클래스).
잘못된 오버라이딩.

e. void add(int a, int b) throws NumberException {}
상위 클래스 메서드와 동일한 시그니처를 가지고 있지만, 더 상위 클래스 예외를 던짐 (NumberException은 InvalidNumberException과 NotANumberException의 상위 클래스).
잘못된 오버라이딩.

----------------------------

a. void add(int a, int b) throws InvalidNumberException, NotANumberException {}
상위 클래스 메서드와 동일한 시그니처와 예외를 던짐.
올바른 오버라이딩.

b. void add(int a, int b) throws InvalidNumberException {}
상위 클래스 메서드와 동일한 시그니처를 가지고 있고, 던지는 예외가 더 적음.
올바른 오버라이딩.

c. void add(int a, int b) throws NotANumberException {}
상위 클래스 메서드와 동일한 시그니처를 가지고 있고, 던지는 예외가 더 적음.
올바른 오버라이딩.
 

 

참고

오버라이딩 : 상위 클래스의 메서드를 하위 클래스에서 재정의하는 것

 

오버라이딩 시 주의

1. 메서드 이름: 상위 클래스와 동일해야 한다.

2. 매개변수 목록: 상위 클래스의 메서드와 동일야 한다.

3. 리턴 타입: 상위 클래스의 메서드와 동일야 한다.

4. 접근 제어자: 상위 클래스의 메서드보다 더 제한적인 접근 제어자를 사용할 수 없다.

5. 예외: 상위 클래스의 메서드가 던지는 예외와 같거나, 그 예외의 하위 클래스만을 던질 수 있다.


[8-4] 다음과 같은 메서드가 있을 때, 예외를 잘못 처리한 것은? (모두 고르시오)

void method() throws InvalidNumberException, NotANumberException {} 

class NumberException extends RuntimeException {} 
class InvalidNumberException extends NumberException {} 
class NotANumberException extends NumberException {}
 

a. try {method( );} catch(Exception e) { }

b. try {method( );} catch(NumberException e) { } catch(Exception e) { }

c. try {method( );} catch(Exception e) { } catch(NumberException e) { }

d. try {method( );} catch(InvalidNumberException e){

} catch(NotANumberException e) { }

e. try {method( );} catch(NumberException e) { }

f. try {method( );} catch(RuntimeException e) { }

 

c

 

풀이

c. try {method();} catch(Exception e) { } catch(NumberException e) { }
Exception이 NumberException보다 상위 클래스이므로 Exception이 먼저 잡히면 NumberException은 절대로 실행되지 않음. 잘못된 예외 처리.

----------------------------

a. try {method();} catch(Exception e) { }
Exception은 모든 예외를 포괄하므로 올바른 예외 처리.

b. try {method();} catch(NumberException e) { } catch(Exception e) { }
NumberException이 Exception보다 구체적이므로 올바른 예외 처리.

d. try {method();} catch(InvalidNumberException e) { } catch(NotANumberException e) { }
InvalidNumberException과 NotANumberException은 각각 구체적인 예외이므로 올바른 예외 처리.

e. try {method();} catch(NumberException e) { }
NumberException은 InvalidNumberException과 NotANumberException의 상위 클래스이므로 올바른 예외 처리.

f. try {method();} catch(RuntimeException e) { }
RuntimeException은 NumberException의 상위 클래스이므로 올바른 예외 처리.
 

[8-5] 아래의 코드가 수행되었을 때의 실행결과를 적으시오.

class Exercise8_5 {
	static void method(boolean b) {
		try {
			System.out.println(1);
			if (b)
				throw new ArithmeticException();
			System.out.println(2);
		} catch (RuntimeException r) {
			System.out.println(3);
			return;
		} catch (Exception e) {
			System.out.println(4);
			return;
		} finally {
			System.out.println(5);
		}
		System.out.println(6);
	}
	public static void main(String[] args) {
		method(true);
		method(false);
	} // main
}
 

1
3
5
1
2
5
6

Process finished with exit code 0
 

풀이 : 메서드 로직 처리 흐름

// 메서드 `method` 흐름

1. try 블록
System.out.println(1);이 실행됨
b가 true이면 throw new ArithmeticException();이 실행되어 ArithmeticException이 던져짐
b가 false이면 System.out.println(2);이 실행됨

2. catch 블록
RuntimeException 또는 그 하위 클래스의 예외가 발생하면 첫 번째 catch 블록이 실행됨
System.out.println(3);이 실행되고 return;으로 인해 메서드가 종료됨
Exception 또는 그 하위 클래스의 예외가 발생하면 두 번째 catch 블록이 실행됨
System.out.println(4);이 실행되고 return;으로 인해 메서드가 종료됨

3. finally 블록
예외 발생 여부와 상관없이 finally 블록은 항상 실행됨
System.out.println(5);가 실행됨

4. try-catch-finally 블록 외부의 코드
System.out.println(6);은 catch 블록이 아닌 정상적인 실행 흐름으로 try 블록을 빠져나갈 때만 실행됨

----------------------------

5. method(true) 실행 시
System.out.println(1); 출력
throw new ArithmeticException();로 인해 RuntimeException 발생
첫 번째 catch 블록이 실행되고 System.out.println(3); 출력
return;으로 인해 메서드가 종료되기 전에 finally 블록이 실행되어 System.out.println(5); 출력
메서드 종료
-> 1, 3, 5 출력

6. method(false) 실행 시
System.out.println(1); 출력
if (b) 조건이 false이므로 System.out.println(2); 출력
try 블록이 정상적으로 종료되면서 finally 블록이 실행되고 System.out.println(5); 출력
try-catch-finally 블록 외부의 코드 System.out.println(6); 출력
-> 1, 2, 5, 6 출력
 

[8-6] 아래의 코드가 수행되었을 때의 실행결과를 적으시오.

class Exercise8_6 {
	public static void main(String[] args) {
		try {
			method1();
		} catch (Exception e) {
			System.out.println(5);
		}
	}
	static void method1() {
		try {
			method2();
			System.out.println(1);
		} catch (ArithmeticException e) {
			System.out.println(2);
		} finally {
			System.out.println(3);
		}
		System.out.println(4);
	}
	static void method2() {
		throw new NullPointerException();
	}
}
 

3
5

Process finished with exit code 0
 

풀이

1. method1 호출
2. method2 호출
3. method2에서 NullPointerException 발생
4. method1의 finally 블록 실행 (System.out.println(3);)
5. NullPointerException이 main 메서드로 전달
6. main 메서드의 catch 블록 실행 (System.out.println(5);)
 

[8-7] 아래의 코드가 수행되었을 때의 실행결과를 적으시오.

class Exercise8_7 {
	static void method(boolean b) {
		try {
			System.out.println(1);
			if (b)
				System.exit(0);
			System.out.println(2);
		} catch (RuntimeException r) {
			System.out.println(3);
			return;
		} catch (Exception e) {
			System.out.println(4);
			return;
		} finally {
			System.out.println(5);
		}
		System.out.println(6);
	}
	public static void main(String[] args) {
		method(true);
		method(false);
	} // main
}
 

1

Process finished with exit code 0
 

풀이 : System.exit(0) 이 실행되면 프로그램이 즉시 종료된다.

1. 첫 번째 호출: method(true)
System.out.println(1); 실행 → 출력: 1
if (b)에서 b가 true이므로 System.exit(0); 실행
프로그램이 즉시 종료됨, 이후의 코드는 실행되지 않음

2. 두 번째 호출: method(false)
첫 번째 호출에서 프로그램이 종료되므로 실행되지 않음
 

[8-8] 다음은 1~100사이의 숫자를 맞추는 게임을 실행하던 도중에 숫자가 아닌 영문자를 넣어서 발생한 예외이다. 예외처리를 해서 숫자가 아닌 값을 입력했을 때는 다시 입력을 받도록 보완하라.

1과 100사이의 값을 입력하세요 :50 
더 작은 수를 입력하세요.
1과 100사이의 값을 입력하세요 :asdf 

Exception in thread "main" java.util.InputMismatchException 
at java.util.Scanner.throwFor(Scanner.java:819) 
at java.util.Scanner.next(Scanner.java:1431) 
at java.util.Scanner.nextInt(Scanner.java:2040) 
at java.util.Scanner.nextInt(Scanner.java:2000) 
at Exercise8_8.main(Exercise8_8.java:16)
 
import java.util.Scanner;

class Exercise8_8 {
    public static void main(String[] args) {
        // 1~100 사이의 임의의 값을 얻어서 answer에 저장한다.
        int answer = (int) (Math.random() * 100) + 1;
        int input = 0; // 사용자입력을 저장할 공간
        int count = 0; // 시도횟수를 세기 위한 변수
        do {
            count++;
            System.out.print("1과 100사이의 값을 입력하세요 :");
            input = new Scanner(System.in).nextInt();
            if (answer > input) {
                System.out.println("더 큰 수를 입력하세요 .");
            } else if (answer < input) {
                System.out.println("더 작은 수를 입력하세요 .");
            } else {
                System.out.println("맞췄습니다 .");
                System.out.println("시도횟수는 " + count + "번입니다 .");
                break; // do-while문을 벗어난다
            }
        } while (true);
    }
}
 

import java.util.InputMismatchException;
import java.util.Scanner;

class Exercise8_8 {
    public static void main(String[] args) {
        // 1~100 사이의 임의의 값을 얻어서 answer에 저장한다.
        int answer = (int) (Math.random() * 100) + 1;
        int input = 0; // 사용자입력을 저장할 공간
        int count = 0; // 시도횟수를 세기 위한 변수

        do {
            count++;
            System.out.print("1과 100사이의 값을 입력하세요 :");
            try {
                input = new Scanner(System.in).nextInt();
            }catch (InputMismatchException e){
                System.out.println("숫자를 입력하세요.");
                continue;
            }
            if (answer > input) {
                System.out.println("더 큰 수를 입력하세요 .");
            } else if (answer < input) {
                System.out.println("더 작은 수를 입력하세요 .");
            } else {
                System.out.println("맞췄습니다 .");
                System.out.println("시도횟수는 " + count + "번입니다 .");
                break; // do-while문을 벗어난다
            }
        } while (true);
    }
}
 

풀이

InputMismatchException : 예상 입력 타입과 다른 경우 예외 발생
입력받는 부분에 예외처리가 필요하므로 try-catch 구문으로 묶고, 예외 메시지로 사용자에 경고.
continue를 사용해 roop의 처음으로 돌아가 다시 값을 입력받도록 함.
 

[8-9] 다음과 같은 조건의 예외클래스를 작성하고 테스트하시오.

[참고] 생성자는 실행결과를 보고 알맞게 작성해야한다.

 

클래스명:UnsupportedFuctionException

조상클래스명:RuntimeException

멤버변수:

이름:ERR_CODE

저장값:에러코드

타입:int

기본값:100

제어자:final private

 

메서드

1. 메서드명:getErrorCode

기능:에러코드(ERR_CODE)를 반환한다.

반환타입:int

매개변수:없음

제어자:public

 

2. 메서드명:getMessage

기능:메세지의 내용을 반환한다. (Exception클래스의 getMessage( )를 오버라이딩)

반환타입:String

매개변수:없음

제어자:public

 

public class Exercise8_9 {
    public static void main(String[] args) throws Exception {
        throw new UnsupportedFuctionException("지원하지 않는 기능입니다.", 100);
    }
}

class UnsupportedFuctionException extends RuntimeException{

    private final int ERR_CODE;

    public UnsupportedFuctionException(String msg, int errCode) {
        // 메시지를 조상 클래스 생성자로 전달
        super(msg);
        // 에러 코드를 인스턴스 변수에 저장
        this.ERR_CODE = errCode;
    }
    public int getERR_CODE() {
        return ERR_CODE;
    }

    @Override
    public String getMessage() { // 조상 클래스의 메서드 재정의 
        return "["+ERR_CODE+"]"+super.getMessage();
    }
}
 

참고 : 호출 순서

new UnsupportedFunctionException("지원하지 않는 기능입니다.", 100)
↓
UnsupportedFunctionException 생성자 호출
↓
super(msg) 호출
↓
RuntimeException 생성자 실행 (this.message = message)
↓
this.ERR_CODE = errCode 실행 (ERR_CODE 필드 초기화)
 

[8-10] 예외처리의 정의와 목적에 대해서 설명하시오.

class Exercise8_10 {
    public static void main(String[] args) {
        try {
            method1();
            System.out.println(6);
        } catch (Exception e) {
            System.out.println(7);
        }
    }
    static void method1() throws Exception {
        try {
            method2();
            System.out.println(1);
        } catch (NullPointerException e) {
            System.out.println(2);
            throw e;
        } catch (Exception e) {
            System.out.println(3);
        } finally {
            System.out.println(4);
        }
        System.out.println(5);
    }
    static void method2() {
        throw new NullPointerException();
    }
}
 

2
4
7

Process finished with exit code 0
 

풀이

main 메서드가 method1을 호출합니다.
main 메서드의 try 블록 시작
↓
method1 메서드가 method2를 호출합니다.
method1의 try 블록 시작
↓
method2 메서드가 NullPointerException을 던집니다.
NullPointerException 발생
↓
method1의 첫 번째 catch 블록에서 NullPointerException을 잡습니다.
System.out.println(2); 실행 → 출력: 2
throw e; 실행하여 예외를 다시 던짐.
↓
finally 블록이 실행됩니다.
System.out.println(4); 실행 → 출력: 4
↓
method1 메서드가 예외를 던지기 때문에 System.out.println(5);는 실행되지 않음.
↓
던져진 예외는 main 메서드의 catch 블록에서 잡힘.
System.out.println(7); 실행 → 출력: 7
 

 

반응형