Java Try with Resources
1. try-with-resources 사용
간단히 말해서, auto-closed하면 리소스가 try 내부에서 선언되고 초기화되어야 한다.
1
2
try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
writer.println("Hello World");
2. try–catch-finally를 try-with-resources로 교체
새로운 리소스 사용 시도 기능을 사용하는 간단하고 확실한 방법은 기존의 장황한 try-catch-finally
블록을 대체하는 것이다.
다음 코드 샘플을 비교해 본다.
첫 번째는 일반적인 try-catch-finally
블록이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
Scanner scanner = null;
try {
scanner = new Scanner(new File("test.txt"));
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (scanner != null) {
scanner.close();
}
}
try-with-resources를 사용하는 매우 간결한 새로운 솔루션은 다음과 같다.
1
2
3
4
5
6
7
try (Scanner scanner = new Scanner(new File("test.txt"))) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
3. 여러 리소스 try-with-resources
세미콜론으로 구분하여 try-with-resources
블록에서 여러 리소스를 선언할 수 있다.
1
2
3
4
5
6
try (Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
while (scanner.hasNext()) {
writer.print(scanner.nextLine());
}
}
4. AutoCloseable를 사용하는 사용자 정의 리소스
try-with-resources
블록에 의해 올바르게 처리될 사용자 정의 리소스를 생성하려면 클래스는 Closeable 또는 AutoCloseable 인터페이스를 구현하고 close 메서드를 재정의해야 한다.
1
2
3
4
5
6
public class MyResource implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("Closed MyResource");
}
}
5. 리소스 Closing Order
먼저 정의/획득된 리소스는 마지막에 닫힌다. 이 동작의 예이다.
- Resource 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class AutoCloseableResourcesFirst implements AutoCloseable {
public AutoCloseableResourcesFirst() {
System.out.println("Constructor -> AutoCloseableResources_First");
}
public void doSomething() {
System.out.println("Something -> AutoCloseableResources_First");
}
@Override
public void close() throws Exception {
System.out.println("Closed AutoCloseableResources_First");
}
}
- Resource 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class AutoCloseableResourcesSecond implements AutoCloseable {
public AutoCloseableResourcesSecond() {
System.out.println("Constructor -> AutoCloseableResources_Second");
}
public void doSomething() {
System.out.println("Something -> AutoCloseableResources_Second");
}
@Override
public void close() throws Exception {
System.out.println("Closed AutoCloseableResources_Second");
}
}
- Code
1
2
3
4
5
6
7
8
private void orderOfClosingResources() throws Exception {
try (AutoCloseableResourcesFirst af = new AutoCloseableResourcesFirst();
AutoCloseableResourcesSecond as = new AutoCloseableResourcesSecond()) {
af.doSomething();
as.doSomething();
}
}
- Output
1
2
3
4
5
6
Constructor -> AutoCloseableResources_First
Constructor -> AutoCloseableResources_Second
Something -> AutoCloseableResources_First
Something -> AutoCloseableResources_Second
Closed AutoCloseableResources_Second
Closed AutoCloseableResources_First
6. catch 그리고 finally
try-with-resources
블록은 여전히 catch 및 finally 블록을 가질 수 있으며 이는 기존 try 블록과 동일한 방식으로 작동한다.
7. Java 9 효과적인 최종 변수
Java 9 이전에는 try-with-resources
블록 내에서만 새로운 변수를 사용할 수 있었다.
1
2
3
4
try (Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
// omitted
}
위에 표시된 것처럼 이는 여러 리소스를 선언할 때 특히 장황했다. Java 9 및 JEP 213의 일부로 이제 try-with-resources
블록 내에서 final 또는 심지어 효과적으로 final 변수를 사용할 수 있다.
1
2
3
4
5
final Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
try (scanner;writer) {
// omitted
}
간단히 말해서, 명시적으로 final로 표시되지 않은 경우에도 첫 번째 할당 후 변경되지 않으면 변수는 사실상 final 이다.
위에 표시된 것처럼 scanner 변수는 명시적으로 final로 선언되므로 try-with-resources
블록과 함께 사용할 수 있다. writer 변수는 명시적으로 최종 변수는 아니지만 첫 번째 할당 이후에는 변경되지 않는다. 따라서 writer 변수도 사용할 수 있다.