throws
API를 사용할 때 설계자의 의도에 따라서 예외를 반드시 처리해야 하는 경우가 있다.
위와 같은 예제가 있다. 내용은 out.txt 파일을 읽어서 그것을 화면에 출력하는 내용이라고만 이해하자
컴파일해보면 밑에와 같은 오류가 발생한다
Unhandled exception type FileNotFoundException
이것은 아래 로직에 대한 예외처리가 필요하다는 뜻이다. 파일리더를 살펴보면
Throws는 한국어로는 '던지다'로 번역된다. 위의 내용은 생성자 FileReader의 인자 fileName의 값에 해당하는 파일이 디렉토리이거나 어떤 이유로 사용할 수 없다면 FileNotFoundException을 발생시킨다는 의미다.
이것은 FileReader의 생성자가 동작할 때 파일을 열 수 없는 경우가 생길 수 있고, 이런 경우 생성자 FileReader에서는 이 문제를 처리할 수 없기 때문에 이에 대한 처리를 생성자의 사용자에게 위임하겠다는 의미다. 그것을 던진다(throw)고 표현하고 있다. 따라서 API의 사용자 쪽에서는 예외에 대한 처리를 반드시 해야 한다는 의미다.
위와같이 try ~ catch 문을 추가하여 클래스를 정상적으로 사용할 수 있다
예외를 조금 더 수정해보겠다
전에 예제를 로직을 클래스 B에 담았다. B.run이 FileReader의 생성자와 BufferedReader.readLine가 던진 예외를 try...catch로 처리한다. 즉 B.run이 예외에 대한 책임을 지고 있다. B.run이 예외 처리를 직접 하지 않고 다음 사용자 C.run에게 넘길 수 있다.
B 내부의 try...catch 구문은 제거되었고 run 옆에 throws IOException, FileNotFoundException이 추가되었다. 이것은 B.run 내부에서 IOException, FileNotFoundException에 해당하는 예외가 발생하면 이에 대한 처리를 B.run의 사용자에게 위임하는 것이다. 위의 코드에서 B.run의 사용자는 C.run이다. throw는 위와 같이 예외처리를 다음 사용자에게 넘기는 것이다.
책임을 최종적으로 클래스 C에서 메인으로 넘기는 모습이다. out.txt 파일을 찾을 수 없는 상황은 B.run 입장에서는 어떻게 할 수 있는 일이 아니다. 엔드유저인 애플리케이션의 사용자가 out.txt 파일을 루트 디렉토리에 위치시켜야 하는 문제이기 때문에 애플리케이션의 진입점인 메소드 main으로 책임을 넘기고 있다.
예외 처리는 귀찮은 일이다. 그래서 예외를 다음 사용자에게 전가(throw)하거나 try...catch로 감싸고 아무것도 하지 않고 싶은 유혹에 빠지기 쉽다. 하지만 예외는 API를 사용하면서 발생할 수 있는 잠재적 위협에 대한 API 개발자의 강력한 암시다. 이 암시를 무시해서는 안 된다.
throw는 예외를 발생시키는 명령이다. throw 뒤에는 예외 정보를 가지고 있는 예외 클래스가 위치한다.
Exception중에서 예로 IOException과 ArithmeticException를 선언했다. 이 예제는 컴파일 오류가 발생한다. 이유는 IOException은 try...catch하거나 throw 해야 한다. 즉, IOException은 예외처리를 강제하고 있지만 ArithmeticException은 그렇지 않다.
RuntimeException을 제외한 Exception 클래스의 하위 클래스들과 RuntimeException 클래스의 차이를 자바에서는 checked와 unckecked라고 부른다. 관계를 정리하면 아래와 같다.
checked 예외 - RuntimeException을 제외한 Exception의 하위 클래스
uncheked 예외 - RuntimeException의 하위 클래스
checked 예외는 반드시 예외처리를 해야 되는 것이고, unchecked는 해도되고 안해도 되는 Exception이다. 바로 이 지점이 IOException과 ArithmeticException의 차이점이다. 이유를 살펴보자면
ArithmeticException의 부모 중에 RuntimeException이 있다. 반면에 IOException은 Exception의 자식이지만 RuntimeException의 자식은 아니다. 이런 이유로 IOException은 checked이고 ArithmeticException은 unchekced이다. 즉 예외로 '던질 수 있는' 클래스는 반드시 Throwable 클래스를 상속 받아야 한다.
'Java' 카테고리의 다른 글
Java 기초 입문 9일차 (제네릭, Arraylist) (0) | 2022.12.07 |
---|---|
Java 기초 입문 8일차 (Object, enum, 참조) (0) | 2022.11.27 |
Java 기초 입문 6일차 (Interface, 다형성, Exception, multi catch) (0) | 2022.11.23 |
Java 기초 입문 5일차 (classpath, API, 접근제어자, abstract) (0) | 2022.11.22 |
Java 기초 입문 4일차 (class와 instance의 관계, 지역변수와 전역변수, 상속, 생성자, 오버로딩과 오버라이딩) (0) | 2022.11.21 |