program story

finally 블록에서 예외 발생

inputbox 2020. 8. 22. 08:48
반응형

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

추가 차단을 피하고 싶은 이유는 무엇입니까? finally 블록에는 예외를 발생시킬 수있는 "일반"작업이 포함되어 있고 finally 블록이 완전히 실행되기를 원하므로 예외를 포착해야합니다.

finally 블록이 예외를 던질 것으로 예상하지 않고 예외를 처리하는 방법을 모르는 경우 (스택 추적 만 덤프 할 것임) 예외가 호출 스택에 버블 링되도록합니다 (finally에서 try-catch 제거). 블록).

If you want to reduce typing you could implement a "global" outer try-catch block, which will catch all exceptions thrown in finally blocks:

try {
    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }
} catch (Exception ex) {
    ...
}

After lots of consideration, I find the following code best:

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

That code guarantees following:

  1. The resource is freed when the code finished
  2. Exceptions thrown when closing the resource are not consumed without processing them.
  3. The code does not try to close the resource twice, no unnecessary exception will be created.

If you can you should test to avoid the error condition to begin with.

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

Also you should probably only be catching exceptions that you can recover from, if you can't recover then let it propagate to the top level of your program. If you can't test for an error condition that you will have to surround your code with a try catch block like you already have done (although I would recommend still catching specific, expected errors).


You could refactor this into another method ...

public void RealDoSuff()
{
   try
   { DoStuff(); }
   catch
   { // resource.close failed or something really weird is going on 
     // like an OutOfMemoryException 
   }
}

private void DoStuff() 
{
  try 
  {}
  catch
  {
  }
  finally 
  {
    if (resource != null) 
    {
      resource.close(); 
    }
  }
}

I usually do this:

MyResource r = null;
try { 
   // use resource
} finally {   
    if( r != null ) try { 
        r.close(); 
    } catch( ThatSpecificExceptionOnClose teoc ){}
}

Rationale: If I'm done with the resource and the only problem I have is closing it, there is not much I can do about it. It doesn't make sense either to kill the whole thread if I'm done with the resource anyway.

This is one of the cases when at least for me, it is safe to ignore that checked exception.

To this day I haven't had any problem using this idiom.


try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

Job done. No null tests. Single catch, include acquire and release exceptions. Of course you can use the Execute Around idiom and only have to write it once for each resource type.


Changing Resource from best answer to Closeable

Streams implements Closeable Thus you can reuse the method for all streams

protected void closeQuietly(Closeable resource) {
    if (resource == null) 
        return;
    try {
        resource.close();
    } catch (IOException e) {
        //log the exception
    }
}

참고URL : https://stackoverflow.com/questions/481446/throws-exception-in-finally-blocks

반응형