programing

최종적으로 블록에 예외를 발생시킵니다.

nicescript 2022. 12. 9. 22:10
반응형

최종적으로 블록에 예외를 발생시킵니다.

어떤 우아한 방법으로 예외들을 처리할 수 있을까요?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 );
  }
}

는 보통 저음음음음음음음음음음음 the the the the the the the the the the the 중 하나를 합니다.closeQuietlyorg.apache.commons.io.IOUtils:

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

7 및 7을 resource를 실장하다AutoClosable「Input Stream」(입력 스트림)입니다.

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부터는 최종 블록에서 리소스를 명시적으로 닫을 필요가 없습니다. 대신 리소스 사용 구문을 사용할 수 있습니다.리소스로 시도 문은 하나 이상의 리소스를 선언하는 시도 문입니다.리소스는 프로그램이 종료된 후 닫아야 하는 개체입니다.리소스 시도 문을 사용하면 각 리소스가 문의 끝에 닫힙니다.java.lang을 구현하는 객체.AutoCloseable: java.io을 구현하는 모든 개체를 포함합니다.닫을 수 있으며 리소스로 사용할 수 있습니다.

다음의 코드를 상정합니다.

try( Connection con = null;
     Statement stmt = con.createStatement();
     Result rs= stmt.executeQuery(QUERY);)
{  
     count = rs.getInt(1);
}

예외가 발생하면 이들 3개의 리소스가 작성된 순서와 반대 순서로 클로즈 메서드가 호출됩니다.즉, 닫힘 메서드는 ResultSetm에 대해 먼저 호출된 후 Statement에 대해 호출되고 Connection 객체에 대해 호출됩니다.

닫힘 메서드가 자동으로 호출될 때 발생하는 모든 예외는 억제된다는 것도 중요합니다.이러한 억제된 예외는 Throwable 클래스에 정의된 getsuppressed() 메서드로 얻을 수 있습니다.

출처 : https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

'최종' 블록에서 발생하는 예외를 무시하는 것은 일반적으로 이러한 예외가 무엇이고 어떤 조건을 나타낼지 모르는 한 좋지 않은 생각입니다.평상시try/finally 패턴, 「」, 「」,try은 외부 하지 못한 , block은 사물을 외부 코드가 예상하지 못한 상태로 .finallyblock은 이러한 상태를 외부 코드가 예상하는 상태로 복원합니다. 모든 normal예를 들어, 어떤 코드가 트랜잭션을 시작하고 나서 두 개의 레코드를 추가하려고 한다고 가정합니다. "finally" 블록은 "committed되지 않은 경우 롤백" 작업을 수행합니다.발신자는, 2번째의 「추가」조작의 실행중에 예외가 발생하는 것에 대비해, 그러한 예외를 검출했을 경우, 어느쪽의 조작이 시행되기 전의 데이타베이스가 되는 것을 상정할 수 있습니다.단, 롤백 중에 두 번째 예외가 발생했을 경우 발신자가 데이터베이스 상태에 대해 어떠한 가정이라도 하면 나쁜 일이 발생할 수 있습니다.롤백 실패는 중대한 위기를 나타냅니다.이것은 단순히 "레코드 추가 실패" 예외를 기대하는 코드로 포착되어서는 안 됩니다.

개인적으로는 발생하는 예외를 최종적으로 포착하여 'Cleanup Failed Exception'으로 포장하는 것이 바람직합니다.이러한 실패는 중대한 문제이며, 이러한 예외를 가볍게 포착해서는 안 된다는 것을 인식하고 있습니다.

두 개의 예외가 서로 다른 클래스인 경우 하나의 솔루션

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

추가 블록을 피하려는 이유는 무엇입니까?최종 블록에는 예외를 발생시킬 수 있는 "정상" 연산이 포함되어 있고 최종 블록을 완전히 실행하려면 예외를 포착해야 합니다.

최종 블록이 예외를 발생시킬 것으로 예상하지 않고 예외 처리 방법을 모를 경우(스택트레이스를 덤프하기만 하면 됩니다), 예외가 콜스택을 버블업합니다(최종 블록에서 트라이캐치를 삭제합니다).

입력을 줄이려면 "글로벌" 외부 트라이캐치 블록을 구현하면 최종 블록에 던져진 모든 예외를 포착할 수 있습니다.

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

이 코드는 다음을 보증합니다.

  1. 코드가 완료되면 리소스가 해방됩니다.
  2. 리소스를 닫을 때 발생하는 예외는 처리하지 않으면 사용되지 않습니다.
  3. 코드는 리소스를 두 번 닫으려고 시도하지 않으며 불필요한 예외가 생성되지 않습니다.

가능하면 에러 상태를 회피하기 위해 테스트해야 합니다.

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 block으로 둘러싸야 합니다(특정하고 예상되는 에러를 검출하는 것을 추천합니다).

이것을 다른 방법으로 리팩터링할 수 있습니다.

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

저는 보통 이렇게 해요.

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 테스트는 없습니다.단일 캐치, 획득 및 해제 예외 포함.물론 Execute Around 관용구를 사용할 수 있으며 리소스 유형별로 한 번만 작성하면 됩니다.

변화하는Resource최선의 답변에서 까지

스트림 실장Closeable따라서 모든 스트림에 대해 메서드를 재사용할 수 있습니다.

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

리소스로 try를 사용할 수 없는 비슷한 상황이 발생했지만 closeQuiet 메커니즘처럼 로그나 무시만 하는 것이 아니라 클로즈에서 발생하는 예외를 처리하고 싶었습니다.저에게는 출력 스트림을 실제로 처리하지 않기 때문에 클로즈에서 발생하는 장애는 단순한 스트림보다 더 중요합니다.

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

언급URL : https://stackoverflow.com/questions/481446/throws-exception-in-finally-blocks

반응형