[java] finally 블록에서 예외 발생

finally블록 에서 발생하는 예외를 처리하는 우아한 방법이 있습니까?

예를 들면 :

try {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
finally {
   try{
     resource.close();
   }
   catch( Exception ex ) {
     // Could not close the resource?
   }
}

블록 에서 try/ catch를 어떻게 피 finally합니까?



답변

나는 보통 다음과 같이한다.

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 );
  }
}


답변

나는 일반적으로 다음 closeQuietly방법 중 하나를 사용합니다 org.apache.commons.io.IOUtils.

public static void closeQuietly(OutputStream output) {
    try {
        if (output != null) {
            output.close();
        }
    } catch (IOException ioe) {
        // ignore
    }
}


답변

Java 7을 사용하고를 resource구현하는 AutoClosable경우 다음을 수행 할 수 있습니다 (예 : InputStream 사용).

try (InputStream resource = getInputStream()) {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}


답변

의심의 여지가 있지만 예외가 발생하도록하고 메서드 내에서 아무것도 기록 할 수없는 경우 유용 할 수 있습니다 (예 : 라이브러리이므로 호출 코드가 예외 및 로깅을 처리하도록하려는 경우).

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 그는 한 단계 더 나아가 두 예외를 하나로 결합하여 어떤 경우에 유용하다는 것을 알 수 있습니다.


답변

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 */ }
 }