본문은 Effective Java를 읽고 간단하게 정리한 글입니다. 필요에 따라 생략/수정된 부분이 있을 수 있으며, 내용이 추후 변경될 수 있습니다.
선결론
- 자바의 라이브러리에는 close 메서드를 호출해서 사용자가 직접 닫아줘야 하는 자원이 많다
- InputStream, OutputStream, java.sql.Connection
- 기존에는 try-finally가 많이 쓰였지만, 많은 문제가 있었다
- 따라서 자바7부터 새롭게 등장한 try-with-resources를 사용하자
기존의 try-finally
아래는 기존의 try-finally를 이용해 직접 자원을 닫는 예제다
public class Item9 {
public static void main(String[] args) {
Connection connection = new Connection();
try {
connection.getConnection();
} finally {
connection.close();
}
}
}
class Connection {
public void getConnection() {
System.out.println("Get Connection");
}
public void close() {
System.out.println("Close Connection");
}
}
/**
* 결과
* Get Connection
* Close Connection
*/
이는 복수의 자원을 사용하는 경우에 두 가지 문제를 가진다
- 중첩된 try-finally 블럭의 사용으로 인해 가독성을 크게 저해한다
- 디버깅을 어렵게 만든다
위의 문제 중 '디버깅을 어렵게 만든다'라는 문제를 좀 더 살펴보자
이번엔 코드를 수정해서 getConnection() 메서드와 close() 메서드가 예외를 반환하도록 했다
public class Item9 {
public static void main(String[] args) {
Connection connection = new Connection();
try {
connection.getConnection();
} finally {
connection.close(); // 여기서 발생한 예외만 출력됨
}
}
}
class Connection {
public void getConnection() {
System.out.println("Get Connection");
throw new FirstException();
}
public void close() {
System.out.println("Close Connection");
throw new SecondException();
}
}
/**
* 결과
* Exception in thread "main" Get Connection
* item9.SecondException
* at item9.Connection.close(Item9.java:41)
* at item9.Item9.main(Item9.java:10)
* Close Connection
*/
- 두 번째 예외만 출력되고 첫 번째 예외는 출력되지 않는다
- 이것이 바로 책에서 말하는 "두 번째 예외가 첫 번째 예외를 집어삼키는 상황"이다
- 한 개의 자원을 사용했음에도 이러한 문제가 발생했다 -> 매우 많은 자원을 사용한다면 엄청나게 복잡한 문제가 발생할 것이다
try-with-resources 적용하기
try-with-resources 구조를 사용하려면 해당 자원이 AutoCloseable 인터페이스를 구현하면 된다
AutoCloseable 인터페이스는 close 메서드 하나만 정의된 인터페이스다
public class Item9 {
public static void main(String[] args) {
try (Connection connection = new Connection()) {
connection.getConnection(); // 둘 다 출력됨
}
}
}
class Connection implements AutoCloseable{
public void getConnection() {
System.out.println("Get Connection");
throw new FirstException();
}
@Override
public void close() {
System.out.println("Close Connection");
throw new SecondException();
}
}
/**
* 결과
* Exception in thread "main" Get Connection
* item9.FirstException
* Close Connection
* at item9.Connection.getConnection(Item9.java:36)
* at item9.Item9.main(Item9.java:7)
* Suppressed: item9.SecondException
* at item9.Connection.close(Item9.java:42)
* at item9.Item9.main(Item9.java:6)
*/
- 불필요한 finally문이 제거되어 코드가 더욱 간결해졌다
- FirstException과 SecondException이 모두 출력되었다
- 특히, FirstException이 먼저 출력되고 SecondException은 Suppressed문과 함께 출력되어 디버깅이 편해졌다
try-with-resources는 복수의 자원을 사용할 때도 사용이 가능하다
이때 try-with-resources의 장점이 더욱 잘 나타난다
public class Item9 {
public static void main(String[] args) {
try (
Connection connection1 = new Connection();
Connection connection2 = new Connection();
) {
connection1.getConnection();
connection2.getConnection();
}
}
}
'책 > Effective Java' 카테고리의 다른 글
[이펙티브 자바] 아이템11: equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2022.04.22 |
---|---|
[이펙티브 자바] 아이템10: equals는 일반 규약을 지켜 재정의하라 (0) | 2022.04.20 |
[이펙티브 자바] 아이템7: 다 쓴 객체 참조를 해제하라 (0) | 2022.04.19 |
[이펙티브 자바] 아이템6: 불필요한 객체 생성을 피하라 (0) | 2022.04.18 |
[이펙티브 자바] 아이템5: 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.04.18 |