프로그래밍/Java

[Java] Try-with-resources 리소스 자동 반납(해제)

Lim-Ky 2021. 12. 6. 23:59
반응형

안녕하세요~ Limky입니다.


최근 코드리뷰를 해주신 과장님께서 Java 7 부터 생긴 Try-with-resources 를 이용해보라는 피드백을 받았습니다.
그래서 알아봤더니, 자바에서 리소스를 사용하고 닫아주는 코딩을 했을때 만약 해당 리소스 객체가 AutoCloseable 인터페이스를 상속받은 구현클래스라면 try-catch 구문 안에서 자동으로 리소스를 반납해준다는 내용이었습니다.

Try-with-resources 사용 조건 요약!!

1. 자바 7 부터 지원 가능

2. try( ) 블록안에 리소스 객체를 할당 받아라

3. 해당 리소스 객체는 AutoCloseable 인터페이스를 상속받은 구현클래스여야 함


이게 무슨말이냐구요?? 코드를 보시면 쉽게 이해가 되실겁니다.

코드 리뷰를 받기전 코드입니다.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class TryWithResources {
	public static void main(String[] args) {
		Scanner sc = null;
		try {
			sc = new Scanner(new File("text.txt"));
			System.out.println(sc.nextLine());
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}finally {
			//scanner 자원 반납
			if(sc != null){
				sc.close();
			}
		}	
	}
 }

보시다시피 일반적으로 file을 읽어서 Scanner 에 담고 해당 Scanner 객체에서 전달받은 파일을 출력하는 코딩입니다.
모든 처리(성공 또는 실패)가 완료되고 난 후에 finally 코드 블록을 타게되고 Scanner 객체를 반납하는 것으로 코드는 끝이 납니다. 하지만 여기서 만약 개발자 미스로 인해 리소스를 해제하지 않으면 자원 누수가 발생하게 됩니다.
또 만약 리소스 객체가 한개가 아닌 여러개라면 개발자의 코드 관리포인트가 늘어나기 때문에 누락이 발생될 가능성이 높아집니다.

따라서, 이를 방지하고자 java7에서 try-catch문안에서 AutoCloseable 인터페이스를 상속받은 리소스라면 자동으로 자원해제를 해줍니다. 공식적으로 Try-with-resources 라고 부르는데 위 코드를 Try-with-resources 구문으로 수정해보겠습니다.

Try-with-resources 적용한 코드..

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class TryWithResources {
	public static void main(String[] args) {
		try (Scanner sc = new Scanner(new File("text.txt"))){
			System.out.println(sc.nextLine());
	
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
	}
}

한눈에 봐도 코드량이 적어졌고 깔끔해졌습니다. 그럼 코드 분석을 해보도록 하겠습니다. 우선 리소스에 해당하는 객체 Scanner를 try( ) 블록안에서 할당받도록 하여 이 리소스 객체는 알아서 자원 해제를 해줘 라는 요청을 자연스럽게 했습니다. 그 다음 과연 Scanner 클래스는 AutoCloseable 인터페이스를 상속받은 객체인지 확인해볼까요??
java docs 사이트에 가서 Scanner 클래스의 근본을 찾아보겠습니다. AutoCloseable 를 상속받은 클래스로 확인되네요.

AutoCloseable을 상속받은 Scanner

https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html

따라서, Scanner 객체는 개발자가 별도의 자원해제를 하지 않아도 자동으로 자원을 해제하도록 코딩을 하게되었습니다.

한 걸음 더....
만약, 자원을 자동으로 해제해주는데 자동을 해제할때 별도의 로그를 찍거나, 자원 해제시 별도의 코딩을 해야한다면? 어떻게할까요? 간단합니다. 사용자가 AutoCloseable 인터페이스를 직접 구현한 리소스 객체를 만들면 됩니다. 아래 간단한 코딩을 보겠습니다.

반응형

AutoCloseable 인터페이스를 구현한 UserResource.class


public class UserResource implements AutoCloseable {

	public UserResource(){
		System.out.println("UserResource create!");
	}

	public void action(){
		System.out.println("UserResource action!!");
	}
	@Override
	public void close() throws Exception {
		System.out.println("UserResource close!!!");
		
	}

}
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class TryWithResources {
	public static void main(String[] args) {
		try (UserResource rc = new UserResource()){
			rc.action();
	
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

결과
UserResource create!
UserResource action!!
UserResource close!!!

위 코드 결과를 보면, UserResource 객체를 try( ) 구문에서 할당받고, 자연스럽게 리소스를 해제하면서 구현한 UserResource 클래스만의 close( ) 메서드를 호출하는 것을 확인할 수 있습니다.

리소스 자원 해제시 깔끔하고 스마트하게 코딩하고 싶다면 Try-with-resources를 활용하시길 추천드립니다. ㅎㅎ

반응형