답변:
나는 보통 다음과 같이한다.
try {
// Use the resource.
} catch( Exception ex ) {
// Problem with the resource.
} finally {
// Put away the resource.
closeQuietly( resource );
}
기타 :
protected void closeQuietly( Resource resource ) {
try {
if (resource != null) {
resource.close();
}
} catch( Exception ex ) {
log( "Exception during Resource.close()", ex );
}
}
Resource
=> Closeable
?
나는 일반적으로 다음 closeQuietly
방법 중 하나를 사용합니다 org.apache.commons.io.IOUtils
.
public static void closeQuietly(OutputStream output) {
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// ignore
}
}
의심의 여지가 있지만 예외가 발생하도록하고 메서드 내에서 아무것도 기록 할 수없는 경우 유용 할 수 있습니다 (예 : 라이브러리이므로 호출 코드가 예외 및 로깅을 처리하도록하려는 경우).
Resource resource = null;
boolean isSuccess = false;
try {
resource = Resource.create();
resource.use();
// Following line will only run if nothing above threw an exception.
isSuccess = true;
} finally {
if (resource != null) {
if (isSuccess) {
// let close throw the exception so it isn't swallowed.
resource.close();
} else {
try {
resource.close();
} catch (ResourceException ignore) {
// Just swallow this one because you don't want it
// to replace the one that came first (thrown above).
}
}
}
}
업데이트 : 나는 이것에 대해 조금 더 조사했고 이것에 대해 나보다 더 명확하게 생각한 누군가로부터 훌륭한 블로그 게시물을 발견했습니다 : http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make -mess-of-stream.html 그는 한 단계 더 나아가 두 예외를 하나로 결합하여 어떤 경우에 유용하다는 것을 알 수 있습니다.
ignore
예외를 기록합니다
Java 7에서는 더 이상 finally 블록 에서 리소스를 명시 적으로 닫을 필요가 없습니다. 대신 try -with-resources 구문을 사용할 수 있습니다 . try-with-resources 문은 하나 이상의 리소스를 선언하는 try 문입니다. 리소스는 프로그램이 완료된 후 닫아야하는 개체입니다. try-with-resources 문은 문 끝에서 각 리소스가 닫히도록합니다. java.io.Closeable을 구현하는 모든 객체를 포함하는 java.lang.AutoCloseable을 구현하는 모든 객체를 리소스로 사용할 수 있습니다.
다음 코드를 가정하십시오.
try( Connection con = null;
Statement stmt = con.createStatement();
Result rs= stmt.executeQuery(QUERY);)
{
count = rs.getInt(1);
}
예외가 발생하면 이 세 가지 리소스 각각에 대해 생성 된 순서와 반대로 close 메서드가 호출됩니다. 이는 close 메소드가 ResultSetm에 대해 먼저 호출 된 다음 Statement에 대해 그리고 마지막에 Connection 객체에 대해 호출됨을 의미합니다.
close 메서드가 자동으로 호출 될 때 발생하는 모든 예외가 억제된다는 것을 아는 것도 중요합니다. 이러한 억제 된 예외는 Throwable 클래스에 정의 된 getsuppressed () 메서드 로 검색 할 수 있습니다 .
출처 : https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
'최종'블록에서 발생하는 예외를 무시하는 것은 일반적으로 예외가 무엇이고 어떤 조건을 나타낼 지 알지 못하는 한 일반적으로 나쁜 생각 입니다. 정상적인 try/finally
사용 패턴에서 try
블록은 외부 코드가 기대하지 않는 상태로 사물을 배치하고 finally
블록은 이러한 사물의 상태를 외부 코드가 예상하는 상태로 복원합니다. 예외를 포착하는 외부 코드는 일반적으로 예외에도 불구하고 모든 것이normal
상태. 예를 들어, 일부 코드가 트랜잭션을 시작한 다음 두 개의 레코드를 추가하려고한다고 가정합니다. "finally"블록은 "커밋되지 않은 경우 롤백"작업을 수행합니다. 호출자는 두 번째 "추가"작업을 실행하는 동안 예외가 발생하도록 준비 할 수 있으며 이러한 예외를 포착하면 데이터베이스가 두 작업을 시도하기 전의 상태가 될 것으로 예상 할 수 있습니다. 그러나 롤백 중에 두 번째 예외가 발생하면 호출자가 데이터베이스 상태에 대해 가정하면 나쁜 일이 발생할 수 있습니다. 롤백 실패는 단순한 "레코드 추가 실패"예외를 예상하는 코드로 포착해서는 안되는 중대한 위기를 나타냅니다 .
내 개인적인 성향은 finally 메서드가 발생하는 예외를 포착하고 "CleanupFailedException"으로 래핑하여 이러한 실패가 주요 문제를 나타내며 그러한 예외를 가볍게 포착해서는 안된다는 것을 인식하는 것입니다.
두 개의 예외가 두 개의 다른 클래스 인 경우 하나의 솔루션
try {
...
}
catch(package1.Exception err)
{
...
}
catch(package2.Exception err)
{
...
}
finally
{
}
그러나 때로는이 두 번째 시도를 피할 수 없습니다. 예 : 스트림 닫기
InputStream in=null;
try
{
in= new FileInputStream("File.txt");
(..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
}
catch(SQLException err)
{
//handle exception
}
finally
{
//at the end, we close the file
if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
}
추가 차단을 피하고 싶은 이유는 무엇입니까? finally 블록에는 예외를 발생시킬 수있는 "정상"작업이 포함되어 있고 finally 블록이 완전히 실행되기를 원하므로 예외를 포착해야합니다.
finally 블록이 예외를 던질 것으로 예상하지 않고 예외를 처리하는 방법을 모르는 경우 (스택 추적 만 덤프 할 것임) 예외가 호출 스택을 위로 올리도록합니다 (finally 블록에서 try-catch 제거 블록).
타이핑을 줄이고 싶다면 finally 블록에서 발생하는 모든 예외를 포착하는 "전역"외부 try-catch 블록을 구현할 수 있습니다.
try {
try {
...
} catch (Exception ex) {
...
} finally {
...
}
try {
...
} catch (Exception ex) {
...
} finally {
...
}
try {
...
} catch (Exception ex) {
...
} finally {
...
}
} catch (Exception ex) {
...
}
많은 고려 끝에 다음 코드가 가장 좋습니다.
MyResource resource = null;
try {
resource = new MyResource();
resource.doSomethingFancy();
resource.close();
resource = null;
} finally {
closeQuietly(resource)
}
void closeQuietly(MyResource a) {
if (a!=null)
try {
a.close();
} catch (Exception e) {
//ignore
}
}
이 코드는 다음을 보장합니다.
가능한 경우 오류 조건을 피하기 위해 테스트해야합니다.
try{...}
catch(NullArgumentException nae){...}
finally
{
//or if resource had some useful function that tells you its open use that
if (resource != null)
{
resource.Close();
resource = null;//just to be explicit about it was closed
}
}
또한 복구 할 수있는 예외 만 포착해야합니다. 복구 할 수없는 경우 프로그램의 최상위 수준으로 전파됩니다. 오류 조건을 테스트 할 수없는 경우 이미 수행 한 것처럼 try catch 블록으로 코드를 둘러싸 야합니다 (예상되는 특정 오류를 포착하는 것이 좋습니다).
나는 보통 이것을한다 :
MyResource r = null;
try {
// use resource
} finally {
if( r != null ) try {
r.close();
} catch( ThatSpecificExceptionOnClose teoc ){}
}
이론적 근거 : 자원을 다 썼고 내가 가진 유일한 문제는 그것을 닫는 것이라면 내가 할 수있는 일이 많지 않다. 어쨌든 리소스를 다 사용했다면 전체 스레드를 죽이는 것도 말이되지 않습니다.
이것은 적어도 나를 위해 선택된 예외를 무시하는 것이 안전한 경우 중 하나입니다.
오늘날까지이 관용구를 사용하는 데 아무런 문제가 없었습니다.
try {
final Resource resource = acquire();
try {
use(resource);
} finally {
resource.release();
}
} catch (ResourceException exx) {
... sensible code ...
}
완료되었습니다. null 테스트가 없습니다. 단일 catch, 획득 및 해제 예외 포함. 물론 Execute Around 관용구를 사용할 수 있으며 각 리소스 유형에 대해 한 번만 작성하면됩니다.
리소스로 try를 사용할 수없는 비슷한 상황이 발생했지만 closeQuietly 메커니즘처럼 로그하고 무시하는 것이 아니라 닫기에서 오는 예외를 처리하고 싶었습니다. 제 경우에는 실제로 출력 스트림을 처리하지 않으므로 닫기 실패가 단순한 스트림보다 더 중요합니다.
IOException ioException = null;
try {
outputStream.write("Something");
outputStream.flush();
} catch (IOException e) {
throw new ExportException("Unable to write to response stream", e);
}
finally {
try {
outputStream.close();
} catch (IOException e) {
ioException = e;
}
}
if (ioException != null) {
throw new ExportException("Unable to close outputstream", ioException);
}