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

사용 후에 반납해줘야 하는 자원들은 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 문법을 추가하였다. 자바는 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문을 사용하는 것이 적합하다.