2017-11-26 2 views
3

예전에는 리소스를 사용해야했던 곳에서 try 블록에서 선언하고 try 블록에서 만든 후 finally 블록에서 닫았습니다. 이 경우 닫는 것이 실패하면 내부 try 블록에 넣습니다.리소스 닫기가 실패 할 경우 java가 수행하는 작업은 무엇입니까?

Resource r=null; 
try{ 
    r=new Resource(); 
    use(r); 
} 
catch(){ 
    outputAndLog(something); 
} 
finally{ 
    if(r != null){ 
     try{ 
     } 
     catch(){ 
      outputAndLog(somethingElse); 
     } 
    } 
} 

이제 우리는

try(Resource r = new Resource()){ 

자바 구문을 사용할 수 있습니다. 그리고 블록은 마침내 우리에게 보이지 않게됩니다. 그러나 그 안에 무엇이 들어 있습니까? 폐쇄가 실패하면 어떻게 될까요?

답변

0

Java tutorials에 따르면 예외가 try 블록에서 발생합니다 하나 개 이상의 예외는 시도 -과 - 자원 문에서 발생하는 경우

, 다음 그 예외는 try-에서 던져 with-resources 문은 이며 블록에 의해 throw 된 예외는 이 던져진 것입니다 ... try 블록에 의해 throw 된 예외에서 Throwable.getSuppressed 메서드를 호출하여 이러한 억제 된 예외를 검색 할 수 있습니다.

3

자원 : 모든 Link


첫째, try-with-resources 실제로 처리하지 않는 Exceptions (이 기록하여 코드에서 수행처럼). 기본적으로 try-catch-finally 구조체에서 처리 할 수있는 객체로 Exceptions을 던져 넣은 이 포함되어 있습니다. Exceptions이 포함되어 있습니다.

try 블록이 Exception을 throw하면 리소스가 닫히고 결과는 Exception이 표시되지 않습니다. 따라서 던진 Exception 개체는 억제 된 Exception에 대한 참조를 갖게됩니다.
try 블록이 Exception을 던지지 않으면 리소스가 닫히고 Exception이 다시 처리됩니다.

따라서 우리는 당신의 예 하지 동일하다는 것을 결론을 내릴 수 있습니다
사용 try-catch-finallyException 동안 같은 try-with-resources 문, 그냥 가까운 오류 '로 처리됩니다 성공적으로 처리 한 후 폐쇄에 의한 Exception 것 실제 처리에서 발생한 Exception과 동등하게 처리되어야합니다.

TL; DR
자원의 폐쇄를 처리하는 것이 더 물건를 포함하는 경우 try-with-resources 문은 좋은 오래된 try-catch-finally로 발생하지 않는 버그를 생성 할 수 있습니다. 예를 들어 내용이 인 경우 jdbc 연결을 커밋하고 롤백하는 것입니다.그래서


는 마침내 정확한 상응하는 것

try(Resource resource = new Resource()){ 
    // other code 
} 

를 들어, 어떤 코드를 생성합니다 :

{ 
    Resource resource = null; 
    Exception exc = null; 
    try { 
     resource = new Resource(); 
     // other code 
    } catch (Exception e) { 
     exc = e; 
     throw e; 
    } finally { 
     if (resource != null) { 
      if (exc != null) { 
       try { 
        resource.close(); 
       } catch (Throwable t) { 
        exc.addSuppressed(t); 
       } 
      } else { 
       resource.close(); 
      } 
     } 
    } 
} 
+1

내가 알고있는 것처럼 [JLS 14.20.3] (https://docs.oracle.com/javase/specs/jls/se8/ html/jls-14.html # jls-14.20.3)'리소스가 null이 아닌 값으로 초기화 된 경우에만 닫힙니다. ', finally 블록에서'resource! = null'을 확인해야합니다. 내가 잘못? – Bedla

+0

네 말이 맞아. 편집 할게. 이것이'try-with-resources' 문을 사용해야하는 이유의 좋은 예라고 생각합니다. 자주 재현하려고하면 버그가 발생합니다. – Izruo

1

그러나 그것은 무엇인가? 폐쇄가 실패하면 어떻게됩니까

try { 
    Resource resource = initResource(); 
    Object possibleExceptionFromTry = null; 
    ... 
    if (stream != null) { 
     if (possibleExceptionFromTry != null) { 
      try { 
       stream.close(); 
      } catch (Throwable exceptionFromClosing) { 
       ((Throwable)possibleExceptionFromTry).addSuppressed(exceptionFromClosing); 
      } 
     } else { 
      stream.close(); 
     } 
    } 
} catch (IOException exception) { ... } 

? 모든 try에서 잘 통과하면

, 당신은 catchResource#close()에서 예외를 잡을 것입니다. 그렇지 try에서 예외 Resource#close에서 발생 예외를 억제 Throwable#getSuppressed함으로써 얻어 질 수있는 배열에 넣어 것이다 java.lang.AutoClosable 인터페이스 방법 close 구현 부르고

} catch (IOException exception) { 
    final Throwable[] suppressedExceptions = exception.getSuppressed(); 
    // exception = the exception from try 
    // suppressedExceptions = the last exception (if any) is likely caused by closing 
} 
0

시적으로 리소스들. JLS 14.20.3

자료에서

는 것과 역순으로 폐쇄되는 그들은 초기화 이었다. 리소스가 null이 아닌 값으로 초기화 된 경우에만 닫힙니다. 한 리소스를 닫음으로써 예외가 발생해도 은 다른 리소스가 닫히는 것을 방지하지 못합니다. 이전에예외가 이니셜 라이저, try 블록 또는 리소스 닫음에 의해 throw 된 경우 이러한 예외가 표시되지 않습니다. 귀하의 예를 들어

try(Resource r = new Resource())이 완전 동일해야 :

Resource r = null; 
    Exception ex = null; 
    try { 
     r = new Resource(); 
     use(r); 
    } catch (Exception e){ 
     ex = e; 
    } 
    finally { 
     if (r != null) { 
      try { 
       r.close(); 
      } catch (Exception e) { 
       if (ex!=null){ 
        ex.addSuppressed(e); 
       } else { 
        ex = e; 
       } 
      } 
     } 
     if (ex != null){ 
      throw ex; 
     } 
    } 
관련 문제