네, Java에서는 생성자(constructor)가 예외를 던지는 것이 허용됩니다.
생성자는 객체를 초기화하기 위해 사용되는 특수한 종류의 메서드입니다. new 키워드를 사용해 클래스의 객체를 생성할 때 호출되며, 이렇게 만들어진 객체를 흔히 클래스의 인스턴스(instance)라고 부릅니다. 각 객체는 자신만의 상태(인스턴스 변수)를 가지며, 해당 클래스의 메서드에 접근할 수 있습니다.
생성자에서 예외 던지기
- 체크 예외(checked exception)는 인스턴스를 생성하려는 과정에서 발생할 수 있는 합법적인 문제 상황을 알리는 데 사용됩니다. 반면 언체크 예외(unchecked exception)는 대개 클라이언트 코드나 생성자 자체에 존재하는 버그를 의미합니다.
- 두 경우 모두 객체는 실제로 힙(heap) 공간에 할당되지만, 그 참조는 반환되지 않습니다. 객체는 가비지 컬렉션(garbage collection)이 수행될 때까지 부분적으로만 초기화된 상태로 남게 됩니다. 따라서 생성자 내부에서 this 참조를 통해 객체 자신의 참조를 외부에 저장하는 것은 위험한 행위입니다. 아직 유효하지 않은 상태의 객체에 대한 접근 권한을 노출할 수 있기 때문입니다.
- 생성자 예외와 관련해 또 하나 주목할 점은 리플렉션(reflection)입니다. 예를 들어 test라는 클래스 객체를 통해 기본 생성자(no-arg constructor)를 호출해야 할 때, 우리는 종종 test.newInstance() 메서드를 사용합니다.
- 생성자가 던진 예외는 그대로 변경 없이 전파(propagation)됩니다. 즉, newInstance() 메서드는 자신이 선언하지 않은 체크 예외까지도 던질 수 있습니다.
예제 코드
public class ConstructorExceptionTest {
public ConstructorExceptionTest() throws InterruptedException {
System.out.println("Preparing an Object");
Thread.sleep(1000);
System.out.println("Object is ready");
}
public static void main(String args[]) {
try {
ConstructorExceptionTest test = new ConstructorExceptionTest();
} catch (InterruptedException e) {
System.out.println("Got interrupted...");
}
}
}실행 결과
Preparing an Object Object is ready
위 예제에서 생성자는 InterruptedException이라는 체크 예외를 던질 가능성이 있으므로, 메서드 시그니처에 throws InterruptedException을 명시하고 호출부에서는 try-catch 블록으로 이를 처리하고 있습니다. 스레드가 중단되지 않으면 "Preparing an Object"와 "Object is ready"가 순서대로 출력되고, 중간에 인터럽트가 발생하면 catch 블록의 "Got interrupted..."가 출력됩니다.