참고글
메서드 오버라이딩(Method Overriding)시에 throws문 규칙에 대해
메서드를 오버라이딩 할때에는 상위 클래스나 인터페이스의 메서드 선언부에 따라 그것을 오버라이딩 할때 제약을 받게되는데, 그 중 하나는 예외를 떠넘기는 throws에 대한 규칙입니다.
규칙에 대해 앞서 말하자면 메서드 오버라이딩시에 하위 클래스는 예외를 throws 하지 않거나, 자신이 상속받은 상위 클래스의 메서드보다 같거나 하위의 예외만을 throws할 수 있습니다.
1. 상위클래스의 메서드에서 throws를 선언했더라도 하위클래스는 throws 처리를 하지 않을 수 있다.
2. 하위클래스는 상위클래스의 메서드에서 throws 하는 예외와 같은 예외를 throws 할 수 있다.
3. 하위클래스는 상위클래스의 메서드에서 throws 하는 예외의 하위 예외만 throws 할 수 있다.
4. 하위클래스는 Runtime 예외(Unchecked) 예외를 상위클래스의 메서드와 관계없이 throws 할 수 있다.
한국어인데도 불구하고 말이 매우 어렵기 때문에 바로 예제 코드를 보도록 하겠습니다. 다음과 같이 흔하게 보이는 Parent 클래스가 있습니다. methodA()는 IOException, SQLException 두 가지의 예외를 throws 하고 있습니다.
class Parent {
public void methodA() throws IOException, SQLException {
}
} |
cs |
1번 규칙에 의하면 Parent 클래스의 methodA()를 오버라이딩 하는 Child의 methodA()는 throws를 선언하지 않아도 됩니다. 상위 클래스나 인터페이스는 그것을 구현하는 하위 클래스에 대해 제약을 거는것이기에 상위 클래스에서 선언한 예외의 범위를 넘어서지만 않으면 되기 때문입니다.
class Child extends Parent {
public void methodA() {
}
}
|
cs |
또는 아래와 같이 IOException은 throws하고 SQLException은 선택적으로 선언하지 않을 수 있습니다.
class Child extends Parent {
public void methodA() throws IOException {
}
} |
cs |
2번 규칙에 의하면 Parent에서 throws한 IOException, SQLException를 똑같이 Child에서도 throws 할 수 있습니다.
class Child extends Parent {
public void methodA() throws IOException, SQLException {
}
} |
cs |
단! 1번과 2번규칙을 종합했을때 하위 클래스에서는 상위 클래스보다 상위 예외를 throws할 수 없습니다. 다음 코드를 보면 Child에서 Parent의 methodA()의 IOException보다 상위 예외인 Exception을 throws 했는데, 이런 처리는 불가능합니다.
class Child extends Parent {
public void methodA() throws Exception { //IOException, SQLException 보다 상위예외이므로 X
}
} |
cs |
3번 규칙에 의해서 Child의 methodA()에서는 IOException, SQLException의 하위 예외들을 throws 할 수 있습니다. ZipException과 XmlStreamReaderException 이 두개의 예외는 IOException를 상속받은 하위 예외이므로 선언이 가능하고 SQLException은 Parent에서 선언되어 있기때문에 마찬가지로 Child에서도 선언할 수 있습니다.
class Child extends Parent {
public void methodA() throws ZipException, XmlStreamReaderException, SQLException {
}
} |
cs |
마지막으로 4번 규칙에 따라 RuntimeException과 그 하위 예외들은 상위 클래스와 관계 없이 하위 클래스에서 throws 할 수 있습니다. 이 부분에 대해서는 저도 궁금한 점인데, 아마도 RuntimeException은 메서드를 사용하는 쪽에서 예외 핸들링이 필수가 아니므로(Unchecked Exception) 제약을 걸어두지 않은것으로 예상하고 있습니다.
class Child extends Parent {
public void methodA() throws RuntimeException {
}
} |
cs |
사실 저는 아직까지 예외를 깊게 다뤄본적이 없고 API를 설계하는 수준이 아니기 때문에 아직까지 throws를 이정도까지 생각하면서 사용 해보지는(throws를 사용하기는 하지만) 못했습니다. 특히나 최신의 프레임워크나 라이브러리들은 API에 RuntimeException을 사용하는 추세이기에 throws로 예외를 떠넘길 필요가 없기 때문입니다. 그래도 이러한 예외 처리 개념들이 Java에 있다 라는 정도는 알아두는게 좋지 않을까 생각이 들어 글을 작성해 보았습니다.