BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String str = in.readLine();
다음과 같이 BufferedReader를 통해 입력을 받으려고 할 때, 고려 사항
- IOException이 발생할 수 있다.
- close()를 통해 직접 닫아줘야 하는 자원이다.
그래서, try-finally 문법을 사용해 해당 코드를 수정한다면 다음과 같이 수정할 수 있다.
public String Input() throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
return in.readLine();
} finally {
in.close();
}
}
finally 블록은 try, catch가 끝난 뒤 실행할 로직을 정의하는 블록이기 때문에, IOException을 처리한 뒤, close() 후 종료하게 된다.
❗결함
💥 finally block 내의 에러 발생
public static String Input() throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
return in.readLine();
} finally {
int i = 1 / 0;
System.out.println("close check!");
in.close();
}
}
* close()를 실행하기 전의 finally block 내의 다른 로직에 의해 에러가 발생하면, close()가 실행되지 않을 수 있다.
💥 try 블록에서 발생한 에러를 상위 메서드에서 catch 할 수 없다.
public static void main(String[] args) {
try {
String input = Input();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String Input() throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
throw new IllegalArgumentException();
// return in.readLine();
} finally {
int i = 1 / 0;
System.out.println("close check!");
in.close();
}
}
* 다음과 같이 Input 메서드의 try 블록에서 IllegalArgumentException이 발생하여도 fianlly 블록에서 발생한 ArithemticException을 상위 메서드에서 잡는다.
✔ try-with-resources를 사용하자
위와 같은 try-finally 방식의 단점을 보완하기 위해 Java 7부터는 try-with-resources 방식을 지원한다.
try-with-resources를 사용하기 위해서는 AutoCloseable 인터페이스를 구현해야 하는데, 해당 인터페이스는 close 메서드 하나만을 정의해 놓은 간단한 인터페이스이다.
StringReader 같은 수 많은 자바 라이브러리 및 서드 파티 라이브러리에서는 이미 해당 AutoCloseable을 구현했거나 확장해 두었다.
하나의 자원을 처리하는 try-with-resources 방식은 다음과 같이 작성할 수 있다.
public static String Input() throws IOException {
try (BufferedReader in = new BufferedReader(new InputStreamReader(System.in))) {
return in.readLine();
}
}
복수의 자원을 처리하는 try-with-resources 방식은 다음과 같이 작성할 수 있다.
public static void out() throws IOException {
try (BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out))) {
out.write(in.readLine());
}
}
코드의 가독성이 매우 올라갔고, 실제 디버깅 결과 close()에서 멈추는 것을 확인할 수 있다.
또한 이전의 문제였던 try 내의 오류 역시 해결할 수 있다.
public static String Input() throws Exception {
try (ExampleClass exampleClass = new ExampleClass()) {
throw new IllegalArgumentException();
}
}
static class ExampleClass implements AutoCloseable {
@Override
public void close() throws Exception {
throw new NullPointerException();
}
}
위와 같이, close() 과정에서 발생하는 NullPointerException 예외가 아닌, try 블록에서 발생하는 IllegalArgumentException이 발생하는 것을 알 수 있다. 추가로 NullPointerException이 무시되는 것이 아닌 Suppressed 태그 뒤에 출력되는 것을 확인 할 수 있다.
'이팩티브 자바' 카테고리의 다른 글
[Effective] equals & hashCode (0) | 2023.03.09 |
---|---|
[Effective] 정적 팩터리 메서드 (0) | 2023.03.02 |