개요
안녕하세요! 오늘은 Java의 Try-with-Resources 구문에 대해 자세히 알아보겠습니다. 이 기능은 Java 7에서 도입되어 try 블록 안에 선언된 자원에 대해서 자원의 자동 닫힘을 지원해서 자원 관리를 훨씬 더 쉽고 안전하게 만들어 주었습니다.
1. try-with-resources 사용하기
자원 자동 닫힘 기능을 사용하려면, 간단하게, try 안에서 자원을 생성하면 됩니다.
1try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
2 writer.println("Hello World");
3}
2. try-catch-finally를 try-with-resources로 대체하기
기존의 장황한 try-catch-finally 블록을 간단하게 try-with-resources 블록으로 대체할 수 있습니다.
다음 코드 샘플을 비교해 보겠습니다. 우선 일반적인 try-catch-finally 블록입니다:
1Scanner scanner = null;
2try {
3 scanner = new Scanner(new File("example.txt"));
4 while (scanner.hasNext()) {
5 System.out.println(scanner.nextLine());
6 }
7} catch (FileNotFoundException e) {
8 e.printStackTrace();
9} finally {
10 if (scanner != null) {
11 scanner.close();
12 }
13}
그리고 다음은 try-with-resources를 사용하는 블록인데 매우 간결하게 바뀝니다.
1try (Scanner scanner = new Scanner(new File("test.txt"))) {
2 while (scanner.hasNext()) {
3 System.out.println(scanner.nextLine());
4 }
5} catch (FileNotFoundException e) {
6 e.printStackTrace();
7}
3. 다수의 자원에 대해서 try-with-resources 사용하기
try-with-resources 블록에서 여러 리소스를 세미콜론으로 구분하여 리소스를 선언할 수 있습니다:
1try (Scanner scanner = new Scanner(new File("testRead.txt"));
2 PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
3 while (scanner.hasNext()) {
4 writer.print(scanner.nextLine());
5 }
6}
4. 자동 닫힘을 지원하는 사용자 정의 리소스
try-with-resources 블록에서 올바르게 처리되는 사용자 정의 리소스를 만들려면 클래스가 Closeable 또는 AutoCloseable 인터페이스를 구현하고 close 메서드를 재정의해야 합니다:
1public class MyResource implements AutoCloseable {
2 @Override
3 public void close() throws Exception {
4 System.out.println("MyResource is auto-closed...");
5 }
6}
5. 자원이 닫히는 순서
먼저 정의/획득된 리소스가 마지막에 닫힙니다. 이런 동작은 아래의 예제로 확인할 수 있습니다.
Resource 1:
1public class AutoCloseableResourcesFirst implements AutoCloseable {
2
3 public AutoCloseableResourcesFirst() {
4 System.out.println("Constructor -> AutoCloseableResources_First");
5 }
6
7 public void doSomething() {
8 System.out.println("Something -> AutoCloseableResources_First");
9 }
10
11 @Override
12 public void close() throws Exception {
13 System.out.println("Closed AutoCloseableResources_First");
14 }
15}
Resource 2:
1public class AutoCloseableResourcesSecond implements AutoCloseable {
2
3 public AutoCloseableResourcesSecond() {
4 System.out.println("Constructor -> AutoCloseableResources_Second");
5 }
6
7 public void doSomething() {
8 System.out.println("Something -> AutoCloseableResources_Second");
9 }
10
11 @Override
12 public void close() throws Exception {
13 System.out.println("Closed AutoCloseableResources_Second");
14 }
15}
Test:
1private void orderOfClosingResources() throws Exception {
2 try (AutoCloseableResourcesFirst af = new AutoCloseableResourcesFirst();
3 AutoCloseableResourcesSecond as = new AutoCloseableResourcesSecond()) {
4
5 af.doSomething();
6 as.doSomething();
7 }
8}
Results:
Constructor -> AutoCloseableResources_First
Constructor -> AutoCloseableResources_Second
Something -> AutoCloseableResources_First
Something -> AutoCloseableResources_Second
Closed AutoCloseableResources_Second
Closed AutoCloseableResources_First
6. catch, finally 블록
try-with-resource 구문에서도 기존 try 구문에서처럼 catch, finally 블록을 동일한 방식으로 사용할 수 있습니다.
7. Java 9 - Effectively Final Variables
Java 9 이전에는 try-with-resource 블럭에서 새로 생성한 자원만 사용이 가능했습니다.
1try (Scanner scanner = new Scanner(new File("testRead.txt"));
2 PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
3 // 생략
4}
위에 표시된 것처럼 다수의 리소스를 선언하는 부분에서 특히 장황합니다. Java 9 및 JEP 213부터는 이제 try-with-resources 블록 내에서 final 변수 혹은 effectively final 변수를 사용할 수 있습니다:
1final Scanner scanner = new Scanner(new File("testRead.txt"));
2PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
3try (scanner;writer) {
4 // 생략
5}
간단히 말해, 변수가 명시적으로 final이라고 표시되지 않더라도 첫 번째 할당 후에도 변경되지 않으면 사실상 final 변수가 됩니다.
위와 같이 스캐너 변수는 명시적으로 final로 선언되었으므로 try-with-resource 블록과 함께 사용할 수 있습니다. writer 변수는 명시적으로 final 변수는 아니지만 첫 번째 할당 후에는 변경되지 않습니다. 따라서 writer 변수도 사용할 수 있습니다.
이렇게 Java 9부터는 이미 선언된 effectively final 변수를 try-with-Resources 구문에서 직접 사용할 수 있어, 코드가 더욱 간결해졌습니다.
마무리
try-with-Resources 구문은 자원 관리를 크게 단순화하고, 자원 누수의 위험을 줄여줍니다. 또한 Java 9의 개선사항으로 코드의 가독성이 더욱 향상되었습니다. 이 기능을 적극 활용하여 더 안전하고 깔끔한 코드를 작성해보세요!