[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 {}
내 풀이:
해당 문제는 메서드 오버라이딩의 주의사항 중 예외의 상속에 관한 내용이다.
메서드 오버라이딩 시에는 부모 메서드의 예외 개수와 범위를 모두 고려해서,
자손 메서드가 부모 메서드 보다 같거나 적은 범위의 또는 적은 개수의 예외를 선언할 수 있도록 해야 한다.
본문의 void add(int a, int b)는 InvalidNumberException, NotANumberException 두 개의 예외를 선언하고 있다.
❓a는 옳지 않다. 부모와 같은 범위의 예외를 선언할 수 없다. ➡️ ⭐ 부모 메서드와 자손 메서드 모두 같은 범위의 예외를 선언할 수 있다.
b는 옳다. 부모 메서드 보다 예외의 개수가 적고, 범위도 좁아졌다.
c는 옳다. InvalidNumberException에 대한 예외 선언이 없어지고 NotANumberException만 남았다.
💡d는 옳지 않다. 개수는 줄어들었지만 Exception 예외 선언이 되어 있다. Exception은 모든 예외의 조상이므로, 처리해야하는 예외 개수 자체가 더 많다.
💡e는 옳지 않다. NumberException은 InvalidNumberException의 상위 클래스이므로 더 많은 예외를 처리할 가능성이 있다.
모범 답안 :
정답 - d, e
해설 : 오버라이딩 할 때 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
[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) {}
class Sol_Exercise8_6 {
public static void main(String[] args) {
try {
method1(); //🔥예외가 발생할 가능성이 있는 메소드
} catch (Exception e) {
System.out.println(5); //🔥모든 예외는 Exception에서 무조건 잡힌다.
}
}
static void method1() {
try {
method2(); //🔥method2는 NullPointerException 인스턴스 생성하고 발생시킴
System.out.println(1); //동작X
} catch (ArithmeticException e) { //NullPointerException이 아니기 때문에 타입매치x
System.out.println(2);
} finally { //🔥무조건 실행
System.out.println(3);
}
System.out.println(4); //🔥✔️✔️try-catch-finally 이후이므로 실행❓
} // method1()
static void method2() {
throw new NullPointerException();
}
}
내 풀이 :
main 메서드가 method1을 호출하고 method1이 method2를 호출한다.
동작은 method2 -> method1 -> main 의 세부내용들이 실행될 것이다.
3, 4, 5가 실행된다.
틀린 풀이 :
✔️ 4는 실행되지 않는다.
⭐왜냐하면 method2는 throws가 아닌 throw를 사용해서 예외를 발생시켰기 때문에 try-catch도 없어 비정상 종료된다.
⭐그런데 method1에서도 NullPointerException에 대한 예외처리가 되어있지 않다. 비정상 종료된다.
다만, 그 시점이 중요한데, try의 method2에서 인스턴스 발생 후 try{}블럭은 건너뛰어 catch를 점검한다.
⭐⭐catch에는 NullPointerException를 잡을 것이 없으므로 finally (println(3))를 실행하고 🔥비정상 종료🔥된다.
⭐main에서는 모든 예외를 잡을 수 있는 Exception이 있으므로 5가 실행된다.
틀린 이유 :
예외 발생(throw)과 예외 처리(throws)에 대한 착오가 있었다.
또한 예외처리를 하지 못하면 비정상 종료된다는 것과, 그 종료되는 시점에 대해 명확히 인지하지 못했다.
모범 :
<정답>
3
5
<해설>
main메서드가 method1()을 호출하고, method1()은 method2()를 호출한다.
method2()에서 NullPointerException이 발생했는데, 이 예외를 처리해줄 try-catch블럭이 없으므로
method2()는 종료되고,
이를 호출한 method1()으로 되돌아갔는데 ⭐여기에는 try-catch블럭이 있긴 하지만
NullPointerException을 처리해줄 catch블럭이 없으므로
method1()도 종료⭐되고, 이를 호출한 main메서드로 돌아간다. 이 때 finally블럭이 수행되어 '3'이 출력된다.
class Sol_Exercise8_7 {
static void method(boolean b) {
try {
System.out.println(1); //🔥💧 예외 없음. 실행
if (b)
System.exit(0); //🔥 true일 경우 System.exit 예외 발생. RuntimeException인지 Exception인지 알 수 없다.
System.out.println(2); //💧 false일 때 2가 실행 예외가 발생하지 않으니 catch를 건너뛰고 finally 실행
} catch (RuntimeException r) {
System.out.println(3); //🔥 true
return; // ❓return문이 있어도 finally는 동작? 그럴 것이다. 그러나 try-catch-finally 부분을 실행하고 return될 것.
} catch (Exception e) {
System.out.println(4);
return;
} finally { //🔥💧true, false이든 무조건 실행
System.out.println(5);
}
System.out.println(6); //💡try~catch 블럭 안에서 return이 나오면 여기까지는 도달하지 x
//💧catch안의 return이 동작하지 않고 정상 순서로 프로그램이 진행되니 자동 실행
}
public static void main(String[] args) {
method(true);
method(false);
} // main
}
<내 풀이>
main 단에서 method(true);와 method(false);를 각각 실행했을 때의 결과를 묻고 있다.
🔥method(true)일 때는 1, 3, 5가 실행된다.
💧method(false)일 때는 1, 2, 5, 6이 실행된다.
<내 정답>
1
3
5
1
2
5
6
<모범>
<정답> 1
<해설>
변수 b의 값이 true이므로 System.exit(0);이 수행되어 프로그램이 즉시 종료된다.
이럴 때는 finally 블럭이 수행되지 않는다.
<틀린이유>
💡System.exit(0)은 프로그램 자체를 종료하는 메서드이다.
<궁금점>
❓❓그렇다고 하더라도 method(false)는 실행되어야 하는게 아닌가?
💡 System.exit(0)은 JVM을 강제로 종료시키는 역할을 합니다. 0은 정상적인 종료임을 나타내는 종료 코드입니다.
따라서 해당 코드가 실행되면, 현재 실행 중인 Java 프로그램이 즉시 종료됩니다.
method(true)에서 System.exit(0)이 실행되어 JVM이 강제 종료되면서 프로그램이 바로 종료됩니다.
따라서 method(false)는 실행되지 않습니다.
아이디어 :
💡💡 차이점을 알 수 있다.
단순 예외가 발생한 것이었다면 프로그램이 비정상 종료되지 않았을 것이다.
그러나 System.exit(0)은 JVM 자체를 종료시키는 것이기 때문에 프로그램 자체가 그 즉시 종료된다.
💡[Bonus] 8-9. 조상의 메서드를 오버라이딩할 때는 가능하다면 조상읨 ㅔ서드를 제활용하는 것이 좋다.