[Java] : try-with-resource

dohyoungK·2024년 4월 1일
0

면접 스크립트

목록 보기
20/25

[Java] : try-with-resource


자바 Resource의 예외 처리

resource란 외부의 데이터(DB, Network, File)을 말한다. 이러한 resource들은 자바 내부에 위치한 요소들이 아니므로, 외부 데이터에 접근하려 할 때 예외가 발생할 수 있다.


자바7 이전의 try-catch-finally

사용 후에 반납해줘야 하는 자원들은 Closable 인터페이스를 구현하고 있으며, 사용 후에 close() 메소드를 호출해주어야 한다.

자바7 이전에는 close()에서 발생하는 예외 또한 처리하기 위해 아래처럼 코드가 복잡해지는 문제가 존재했다.

public static void main(String[] args) throws IOException {
    FileInputStream is = null;
    FileOutputStream os = null;

    try {
        is = new FileInputStream("input.txt");
        os = new FileOutputStream("output.txt");

        int data = -1;
        while ((data = is.read()) != -1) {
            System.out.print((char) data);
            os.write(data);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    } finally {
    	// close()에 대한 예외처리도 필요
        if (is != null) is.close();
            
        try {
            os.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

자원 반납에 의한 코드 복잡성 문제 뿐만 아니라 try-catch문은 여러 단점이 존재한다. 에러로 자원을 반납하지 못하는 경우가 발생할 수 있고, 에러 스택 트레이스가 누락되어 디버깅이 어려울 수 있다.

자바7 부터의 try-with-resources

자바는 이러한 문제점을 해결하고자 자바7부터 자원을 자동으로 반납해주는 try-with-resources 문법을 추가하였다. 자바는 AutoCloseable 인터페이스를 구현하고 있는 자원에 대해 try-with-resources를 적용 가능하도록 하였고, 이를 사용함으로써 코드가 유연해지고, 누락되는 에러없이 모든 에러를 잡을 수 있게 되었다.

try 블록에 괄호()를 추가해 자원을 할당하는 코드를 명시하면, 해당 try 블록이 끝나자마자 자동으로 할당된 자원을 해제한다.

public static void main(String[] args) throws IOException {
    try (FileInputStream is = new FileInputStream("input.txt");
         FileOutputStream os = new FileOutputStream("output.txt")) {
        int data = -1;
        while ((data = is.read()) != -1) {
            System.out.print((char) data);
            os.write(data);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

자원을 반납하지 못하는 경우

try-catch-finally 문에서 여러 자원을 사용하고 반납하는 경우 자원의 반납이 이루어지지 않을 수 있다.

public class MyResource implements AutoCloseable{ 
	@Override 
    public void close() throws RuntimeException { 
    	System.out.println("close"); 
    	throw new RuntimeException(); 
    } 
    
    public void hello() { 
    	System.out.println("hello"); 
    } 
}
public static void try1() {
    MyResource myResource1 = null;
    MyResource myResource2 = null;

    try {
        myResource1 = new MyResource();
        myResource2 = new MyResource();
        myResource1.hello();
        myResource2.hello();
    } finally {
        if (myResource1 != null) myResource1.close();

        if (myResource2 != null) myResource2.close();
    }
}

출력
hello
hello
close

이 문제를 해결하기 위해서는 if문으로 null처리한 close() 메서드를 try-catch문을 통해 catch에서 예외처리를 해야하지만 이는 코드를 복잡하게 만든다.

하지만 try-with-resources문은 별도의 처리없이 문제 해결이 가능하다.

public static void try2() {
    try (MyResource myResource1 = new MyResource();
         MyResource myResource2 = new MyResource()) {
        myResource1.hello();
        myResource2.hello();
    }
}

출력
hello
hello
close
close

Java 파일이 Class 파일로 컴파일 될 때 try-with-resources에서 누락없이 모든 경우를 try-catch-finally로 변환해주기 때문에 간단하게 문제 해결이 가능하다. 위에서 직접 구현해주어야 했던 부분을 컴파일러가 처리해준 것이다.


에러 스택 트레이스 누락 경우

try-catch-finally 문을 사용하면 에러가 발생해도 스택 트레이스에 누락되는 경우가 발생할 수 있다.

public class MyResource implements AutoCloseable{ 
	@Override 
    public void close() throws RuntimeException { 
    	System.out.println("close"); 
    	throw new RuntimeException(); 
    } 
    
    public void hello() { 
    	System.out.println("hello"); 
        throw new RuntimeException(); 
    } 
}
public static void try3() {
    MyResource myResource = null;

    try {
        myResource = new MyResource();
        myResource.hello();
    } finally {
        if (myResource != null) myResource.close();
    }
}

try3()를 호출했을 때 예상과는 다르게 hello()에서의 예외는 누락된 채 close()의 예외만 잡히는 것을 볼 수 있다.

하지만 try-with-resources문을 사용하면 누락되는 에러없이 모든 에러가 스택 트레이스에 잡히는 것을 볼 수 있다.

public static void try4() {
    try (MyResource myResource1 = new MyResource()) {
        myResource1.hello();
    }
}

따라서 자원을 반납하는 경우가 생긴다면 코드의 복잡도, 자원 반납 누락, 스택 트레이스 에러 누락 등의 문제가 없는 try-with-resources문을 사용하는 것이 적합하다.

0개의 댓글