참고자료:
try-with-resources 구문을 사용해서 사용한 자원을 반납하는데 효율적으로 반납해보자.
애플리케이션에서 외부 자원을 사용하는 경우 반드시 외부 자원을 해제해야 한다. (예: Database connection)
그래서 항상 try - finally 구문을 사용했다.
try {
//정상 흐름
} catch() {
//예외 흐름
} finally {
//반드시 호출해야 하는 마무리 흐름
}
이런 반복적인 구문을 사용하면서 편의 기능을 자바 7에서 도입했는데 그게 try-with-resources다.
이 구문을 사용하면 try가 끝나는 순간 자원을 알아서 반납해준다.
이 기능을 사용하려면 먼저 AutoClosable 인터페이스를 구현해야 한다.
public interface AutoClosable {
void close() throws Exception;
}
이 인터페이스를 구현한 클래스의 인스턴스를 사용하면 try가 끝나는 시점에 close() 메서드가 자동으로 호출된다.
그리고 다음과 같이 try-with-resources 구문을 사용하면 된다.
try (Resource resource = new Resource()) {
resource.xxx
...
}
직접 이 AutoClosable 인터페이스를 구현해서 try-with-resources를 사용해보자.
package exception.ex4;
import exception.ex4.exception.ConnectExceptionV4;
import exception.ex4.exception.SendExceptionV4;
public class NetworkClientV5 implements AutoCloseable {
private final String address;
private boolean connectError;
private boolean sendError;
public NetworkClientV5(String address) {
this.address = address;
}
public void connect() {
if (connectError) {
throw new ConnectExceptionV4(address, "서버 연결 실패");
}
System.out.println(address + " 서버 연결 성공");
}
public void send(String data) {
if (sendError) {
// throw new RuntimeException("ex");
throw new SendExceptionV4(data, address + " 서버에 데이터 전송 실패: " + data);
}
System.out.println(address + " 서버에 데이터 전송: " + data);
}
public void disconnect() {
System.out.println(address + " 서버 연결 해제");
}
public void initError(String data) {
if (data.contains("error1")) {
connectError = true;
}
if (data.contains("error2")) {
sendError = true;
}
}
@Override
public void close() {
System.out.println("NetworkClientV5.close");
disconnect();
}
}
어떤 클래스던 AutoClosable 인터페이스를 구현하면, 반드시 구현해야 하는 메서드 close()가 있다. 이 close() 메서드에서 원하는 작업(리소스 정리)을 해주면 된다.
저 NetworkClientV5 클래스를 사용하는 코드는 이렇게 생겼다.
package exception.ex4;
public class NetworkServiceV5 {
public void sendMessage(String data) {
String address = "https://example.com";
try (NetworkClientV5 client = new NetworkClientV5(address)) {
client.initError(data);
client.connect();
client.send(data);
} catch (Exception e) {
System.out.println("[에러 발생]: " + e.getMessage());
}
}
}
이렇게 try-with-resources 구문으로 인스턴스를 생성하고 try 구문 안에서 원하는 작업을 다 수행하면 try가 끝나는 시점에 바로 구현한 close() 메서드가 실행된다.
Main
package exception.ex4;
import exception.ex4.exception.SendExceptionV4;
import java.util.Scanner;
public class MainV4 {
public static void main(String[] args) {
NetworkServiceV4 networkService = new NetworkServiceV4();
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("전송할 문자: ");
String input = scanner.nextLine();
if (input.equals("exit")) {
break;
}
try {
networkService.sendMessage(input);
} catch (Exception e) {
exceptionHandler(e);
}
System.out.println();
}
System.out.println("프로그램을 정상 종료합니다.");
}
// 공통 예외 처리
private static void exceptionHandler(Exception e) {
System.out.println("사용자 메시지: 죄송합니다. 알 수 없는 문제가 발생했습니다.");
System.out.println("==개발자용 디버깅 메시지==");
e.printStackTrace(System.out);
// e.printStackTrace();
//필요하면 예외 별로 별도의 추가 처리 가능
if (e instanceof SendExceptionV4 sendExceptionV4) {
System.out.println("[전송 오류] 전송 데이터: " + sendExceptionV4.getData());
}
}
}
실행결과:
전송할 문자:
hello
https://example.com 서버 연결 성공
https://example.com 서버에 데이터 전송: hello
https://example.com 서버 연결 해제
전송할 문자:
error1
https://example.com 서버 연결 해제
사용자 메시지: 죄송합니다. 알 수 없는 문제가 발생했습니다.
==개발자용 디버깅 메시지==
exception.ex4.exception.ConnectExceptionV4: 서버 연결 실패
at exception.ex4.NetworkClientV4.connect(NetworkClientV4.java:18)
at exception.ex4.NetworkServiceV4.sendMessage(NetworkServiceV4.java:11)
at exception.ex4.MainV4.main(MainV4.java:21)
정상 흐름이나, 예외 흐름이나 모두 서버 연결 해제가 잘 호출된다. 그리고 예외 흐름일 때 호출 시점이 중요한데 보면 catch에 걸렸을 때 catch로 가기전 close()메서드가 호출됐음을 확인할 수 있다. 이렇듯 정말 try가 끝나는 즉시 close()메서드가 호출된다.
try-with-resources 장점
- 리소스 누수 방지: 모든 리소스가 제대로 닫히도록 보장한다. 실수로 finally 블록을 적지 않거나 finally 블럭 안에서 자원 해제 코드를 누락하는 문제들을 예방한다.
- 코드 간결성 및 가독성 향상: 명시적인 close() 메서드 호출이 필요 없어 코드가 더 간결하고 읽기 쉬워진다.
- 스코프 범위 한정: 예를 들어 리소스로 사용되는 client 변수의 스코프가 try 블록 안으로 한정된다. 따라서 코드 유지보수가 더 쉬워진다.
- 조금 더 빠른 자원 해제: 기존에는 try - catch - finally 순으로 catch 이후에 자원을 반납하는데 try-with-resources 구문은 try 블록이 끝나면 바로 반납한다.
'JAVA의 가장 기본이 되는 내용' 카테고리의 다른 글
예외 처리 2 (예외 계층) (0) | 2024.04.23 |
---|---|
예외처리 1 (예외처리가 필요한 이유) (0) | 2024.04.23 |
익명 클래스 (0) | 2024.04.21 |
지역 클래스 (0) | 2024.04.21 |
중첩 클래스(정적 중첩 클래스, 내부 클래스) (0) | 2024.04.14 |