DE-labtory / sc

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Share] Try-with-resources

boohyunsik opened this issue · comments

Topic

3장 템플릿 첫 부분에 try-catch가 나와서 참고가 될 만한 try-with-resources에 대해 소개해드리고자 합니다.

Detail

Java를 이용해 외부 자원에 접근하는 경우 한가지 주의해야할 점은 외부자원을 사용한 뒤 제대로 자원을 닫거나 해제해야 한다는 점입니다.

public static void main(String[] args) {
	FileInputStream fis = null;
	try {
		fis = new FileInputStream("test.txt");
	} catch(IOException e) {
		System.out.println("error : " + e.getMessage());
	} finally {
		fis.close();
	}
}

그러나 위 코드에서 fis.close()IOException을 던지기 때문에 다음과 같은 코드가 됩니다.

public static void main(String[] args) {
	FileInputStream fis = null;
	try {
		fis = new FileInputStream("test.txt");
	} catch(IOException e) {
		System.out.println("error : " + e.getMessage());
	} finally {
		try {
			fis.close();
		} catch(IOException e) {
			// Handle error...
		}
	}
}

또한 test.txt 파일이 없는 경우는 fisnull 일 것이기 때문에 null check도 해줘야 합니다.

public static void main(String[] args) {
	FileInputStream fis = null;
	try {
		fis = new FileInputStream("test.txt");
	} catch(IOException e) {
		System.out.println("error : " + e.getMessage());
	} finally {
		try {
			if (fis != null) {
				fis.close();
			}
		} catch(IOException e) {
			// Handle error...
		}
	}
}

코드가 매우 지저분해집니다. 이를 해결하기 위해 JDK 1.7부터는 다음과 같은 인터페이스가 추가되었습니다.

/**
 * @author Josh Bloch
 * @since 1.7
 */
public interface AutoCloseable {
    void close() throws Exception;
}

(저자 Josh Bloch는 Effective Java의 저자입니다.)
이 인터페이스 추가와 더불어 try절에 소괄호가 들어가는 문법이 추가되었습니다.

try(FileInputStream fis = new FileInputStream("test.txt") {
	// Do something if success
} catch(IOException e) {
	// Handle error...
}

다음과 같이 깔끔하게 코드를 작성할 수 있고, close()를 호출하지 않아도 성공적으로 실행했을때나, Exception이 발생했을때 모두 자원을 해제할 수 있습니다.

이제 봤는데 내용 좋네요
몰랐습니다..

공유 감사해요!

오 신기하네요. 완전 꿀팁!

좋은 글 감사합니다!
신기해서 try-with-resource statement에 대해 찾아보다가 추가 내용이 있어 공유합니다!

  1. try-with-resourcetry에 자원 객체(AutoCloseable 인터페이스를 구현한 객체)를 전달하여 try 코드 블록이 끝나면 자동으로 자원을 종료함.
try (SomeResource resource = getResource()) {
    use(resource);
} catch(...) {
    ...
}
  1. try() 안에 여러 개의 자원 객체를 전달할 수 있음.
try(Something1 s1 = new Something1();
    Something2 s2 = new Something2()) {
    ...
} catch(...) {
    ...
}
  1. try 블록과 finally 블록에서 동시에 예외가 발생했을 경우, 기존 try-catch-finally 구문은 finally 블록에서 발생한 예외를 throw 하지만, try-with-resource 구문은 try 블록의 예외를 throw 함.
static String useTry(String path) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

위 코드에서

    try {
        return br.readLine();
    } 

이 부분(br.readLine())과

    finally {
        if (br != null) br.close();
    }

이 부분(br.close())에서 동시에 예외 발생할 수 있음. 이런 경우 br.close()의 예외를 throw 함.

그러나 try-with-resource 구문은 다름.

static String useTryResource(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

위 코드에서

    return br.readLine();

try 블럭 부분(br.readLine())과

    try (BufferedReader br = new BufferedReader(new FileReader(path)))

try resource 부분(new FileReader())에서 동시에 예외 발생할 수 있음. 이런 경우 br.readLine()의 예외를 throw 함.

@hihiboss 마지막 3번에서 br.readline() 에러가아니라 new FileReader()의 exception 을 throw하는게 맞지않앙??

그리고 다들 봣을수있지만 위의 예제처럼 중첩접근에서의 close() 호출순서에대해서
https://multifrontgarden.tistory.com/192
여기 잘나와있어요~ autocloseable 을 impl 할일 있거나 close가 어떻게 각각 일어나는지 궁금하면 참고 하세요