etc./StackOverFlow

finally 블록은 항상 Java에서 실행됩니까?

청렴결백한 만능 재주꾼 2021. 11. 13. 00:14
반응형

질문자 :jonny five


이 코드를 고려할 때 something() finally 블록이 항상 실행된다는 것을 절대적으로 확신 할 수 있습니까?

 try { something(); return success; } catch (Exception e) { return failure; } finally { System.out.println("I don't know if this will get printed out"); }


예, try 또는 catch 코드 블록을 실행한 후 finally

finally 으로 호출되지 않는 유일한 경우는 다음과 같습니다.

  1. System.exit() 를 호출하면
  2. Runtime.getRuntime().halt(exitStatus) 를 호출하면
  3. JVM이 먼저 충돌하는 경우
  4. try 또는 catch 블록에서 무한 루프(또는 다른 인터럽트 불가능하고 종료되지 않는 문)에 도달하는 경우
  5. OS가 JVM 프로세스를 강제 종료하는 경우 예: UNIX kill -9 <pid>
  6. 호스트 시스템이 사망한 경우 예: 정전, 하드웨어 오류, OS 패닉 등
  7. finally 블록이 데몬 스레드에 의해 실행되고 다른 모든 비 데몬 스레드가 finally

jodonnell

예제 코드:

 public static void main(String[] args) { System.out.println(Test.test()); } public static int test() { try { return 0; } finally { System.out.println("finally trumps return."); } }

산출:

 finally trumps return. 0

Kevin

또한 나쁜 습관이지만 finally 블록 내에 return 문이 있으면 일반 블록의 다른 반환보다 우선합니다. 즉, 다음 블록은 false를 반환합니다.

 try { return true; } finally { return false; }

finally 블록에서 예외를 던질 때도 마찬가지입니다.


MooBob42

다음은 Java 언어 사양의 공식 단어입니다.

14.20.2. try-finally 및 try-catch-finally 실행

finally 블록이 있는 trytry 블록을 실행하여 실행됩니다. 그런 다음 선택이 있습니다.

  • try 블록의 실행이 정상적으로 완료되면 [...]
  • Vthrow try 블록의 실행이 갑자기 완료되면 [...]
  • try 블록의 실행이 다른 이유로 R 갑자기 완료되면 finally 블록이 실행됩니다. 그런 다음 선택이 있습니다.
    • finally 블록이 정상적으로 완료되면 이유 R try 문이 갑자기 완료됩니다.
    • finally 블록이 이유 S 로 인해 갑자기 완료되면 try 문이 S 이유 때문에 갑자기 완료 되고 이유 R 은 폐기됩니다 .

return 대한 사양은 실제로 이것을 명시적으로 만듭니다.

JLS 14.17 반환 문

 ReturnStatement: return Expression(opt) ;

Expression 이 없는 return 문은 제어를 포함하는 메서드 또는 생성자의 호출자에게 제어를 전송 하려고 시도합니다.

Expression 있는 return 문은 컨트롤을 포함하는 메서드의 호출자에게 제어를 전송 하려고 시도합니다. Expression 의 값은 메소드 호출의 값이 됩니다.

위의 설명은 어떤이있는 경우 때문에 그냥 "전송 제어"보다는 "전송 제어에 시도"라고 try 방법 또는 생성자 내에서 문 try 를 차단 포함 return 문 후 어떤, finally 사람들의 조항 try 문에서 실행됩니다 제어가 메서드 또는 생성자의 호출자에게 전달되기 전에 가장 안쪽에서 바깥쪽으로 순서입니다. finally 절이 갑자기 완료되면 return 문에 의해 시작된 제어 전송이 중단될 수 있습니다.


polygenelubricants

다른 응답 외에도 'finally'는 try..catch 블록에 의해 모든 예외/반환 값을 재정의할 수 있는 권한이 있음을 지적하는 것이 중요합니다. 예를 들어 다음 코드는 12를 반환합니다.

 public static int getMonthsInYear() { try { return 10; } finally { return 12; } }

마찬가지로 다음 메서드는 예외를 throw하지 않습니다.

 public static int getMonthsInYear() { try { throw new RuntimeException(); } finally { return 12; } }

다음 방법은 그것을 던집니다.

 public static int getMonthsInYear() { try { return 12; } finally { throw new RuntimeException(); } }

Eyal Schneider

다음은 Kevin의 답변에 대한 자세한 설명입니다. 반환될 식은 후에 반환되더라도 finally 전에 평가된다는 것을 아는 것이 중요합니다.

 public static void main(String[] args) { System.out.println(Test.test()); } public static int printX() { System.out.println("X"); return 0; } public static int test() { try { return printX(); } finally { System.out.println("finally trumps return... sort of"); } }

산출:

 X finally trumps return... sort of 0

WoodenKitty

약간 수정하여 위의 예를 시도했습니다.

 public static void main(final String[] args) { System.out.println(test()); } public static int test() { int i = 0; try { i = 2; return i; } finally { i = 12; System.out.println("finally trumps return."); } }

위의 코드는 다음을 출력합니다.

마침내 트럼프가 돌아왔다.
2

return i; 할 때 때문입니다. i 는 값 2를 가집니다. 이 후 finally 블록이 실행되어 i System.out out이 실행됩니다.

finally 블록을 실행한 후 try 블록은 12를 반환하는 대신 2를 반환합니다. 이 반환 문이 다시 실행되지 않기 때문입니다.

Eclipse에서 이 코드를 디버그하면 finally 블록의 System.outtry return 문이 다시 실행된다는 느낌을 받게 됩니다. 그러나 이것은 사실이 아닙니다. 단순히 값 2를 반환합니다.


vibhash

이것이 finally 블록의 전체 아이디어입니다. 물론 돌아가기 때문에 건너뛸 수 있는 정리 작업을 확실히 수행할 수 있습니다.

마지막으로 try 블록에서 발생하는 일 에 관계없이 호출됩니다( System.exit(int) 를 호출하거나 다른 이유로 Java Virtual Machine이 종료 되지 않는 한).


Chris Cooper

이에 대해 논리적으로 생각하는 방법은 다음과 같습니다.

  1. finally 블록에 배치된 코드는 try 블록 내에서 발생하는 모든 작업을 실행해야 합니다.
  2. 따라서 try 블록의 코드가 값을 반환하거나 예외를 발생시키려고 하면 finally 블록을 실행할 수 있을 때까지 항목이 '선반에' 배치됩니다.
  3. finally 블록의 코드는 (정의상) 우선 순위가 높기 때문에 원하는 대로 반환하거나 throw할 수 있습니다. 이 경우 '선반에' 남은 것은 모두 폐기됩니다.
  4. 이에 대한 유일한 예외는 'System.exit'와 같은 시도 블록 동안 VM이 완전히 종료되는 경우입니다.

Garth Gilmour

finally는 비정상적인 프로그램 종료가 없는 한 항상 실행됩니다(예: System.exit(0).. 호출). 따라서 sysout이 인쇄됩니다.


shyam

아니요, 항상 한 가지 예외가 있는 것은 아닙니다. // System.exit(0); finally 블록이 finally 실행을 방지하기 전에.

 class A { public static void main(String args[]){ DataInputStream cin = new DataInputStream(System.in); try{ int i=Integer.parseInt(cin.readLine()); }catch(ArithmeticException e){ }catch(Exception e){ System.exit(0);//Program terminates before executing finally block }finally{ System.out.println("Won't be executed"); System.out.println("No error"); } } }

Rajendra Jadi

또한 최종적으로 반환하면 모든 예외가 발생합니다.http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


James A. N. Stauffer

System.exit(0) 호출로 인해 비정상적인 프로그램 종료가 발생하지 않는 한 항상 실행됩니다.

게다가 finally 블록 내에서 반환된 모든 값은 finally 블록을 실행하기 전에 반환된 값을 무시하므로 try finally를 사용할 때 모든 종료점을 확인하는 데 주의해야 합니다.


user9189

마지막으로 항상 실행된다는 것이 요점입니다. 반환 후 코드에 표시된다고 해서 그렇게 구현되는 것은 아닙니다. try 블록을 종료할 때 이 코드를 실행할 책임이 있습니다.

예를 들어 다음이 있는 경우:

 int foo() { try { return 42; } finally { System.out.println("done"); } }

런타임은 다음과 같은 것을 생성할 것입니다:

 int foo() { int ret = 42; System.out.println("done"); return 42; }

잡히지 않은 예외가 발생하면 finally 블록이 실행되고 예외는 계속 전파됩니다.


Motti

네, 호출됩니다. 이것이 finally 키워드를 갖는 요점입니다. try/catch 블록 밖으로 점프하는 것이 finally 블록을 건너뛸 수 있다면 이는 System.out.println을 try/catch 외부에 두는 것과 같습니다.


Mendelt

System.exit() 를 호출하지 않는 한(또는 스레드가 충돌하지 않는 한) 항상 호출되기 때문입니다.


Jay Riggs

이는 i 값을 12로 할당했지만 i 값을 함수에 반환하지 않았기 때문입니다. 올바른 코드는 다음과 같습니다.

 public static int test() { int i = 0; try { return i; } finally { i = 12; System.out.println("finally trumps return."); return i; } }

Wasim

대답은 간단 YES입니다.

입력:

 try{ int divideByZeroException = 5 / 0; } catch (Exception e){ System.out.println("catch"); return; // also tried with break; in switch-case, got same output } finally { System.out.println("finally"); }

산출:

 catch finally

Meet Vora

간결하게, 공식 Java 문서(여기를 클릭하십시오)에는 다음과 같이 쓰여 있습니다.

try 또는 catch 코드가 실행되는 동안 JVM이 종료되면 finally 블록이 실행되지 않을 수 있습니다. 마찬가지로 try 또는 catch 코드를 실행하는 스레드가 중단되거나 종료되면 응용 프로그램이 전체적으로 계속되더라도 finally 블록이 실행되지 않을 수 있습니다.


bikz05

항상은 아님

Java 언어 사양 try - catch - finallytry - catch 블록이 작동하는 방식을 설명합니다.
finally 블록이 항상 실행되도록 지정하지 않습니다. try - catch - finallytry - finally 블록이 완료되는 모든 경우에 대해 finally 가 실행되어야 함을 지정합니다.

 try { CODE inside the try block } finally { FIN code inside finally block } NEXT code executed after the try-finally block (may be in a different method).

JLS는 FIN 이 CODE 다음에 실행되는 것을 보장하지 않습니다. JLS는 CODENEXT 가 실행되는 경우 FIN 이 항상 CODE 이후 및 NEXT 이전에 실행되도록 보장합니다.

finally 블록이 항상 try 블록 다음에 실행되도록 보장하지 않는 이유는 무엇입니까? 불가능하기 때문입니다. try finally 블록을 실행하기 전에 JVM이 중단(종료, 충돌, 전원 끄기)될 가능성은 거의 없습니다. 이를 피하기 위해 JLS가 할 수 있는 일은 없습니다.

따라서 적절한 동작 try 블록이 완료된 후 항상 실행되는 finally 블록에 의존하는 소프트웨어는 버그가 있습니다.

try return 명령은 이 문제와 관련이 없습니다. 실행은 후 코드에 도달하면 try - catch - finally 이 보장되어있는 것을 finally 블록으로 사용하거나 사용하지 않고, 이전에 실행 된 것입니다 return 내부 지침 try 차단합니다.


Anonymous Coward

네, 그럴 것입니다. 그렇지 않으면 System.exit()가 호출되거나 JVM이 충돌하지 않는 한 try 또는 catch 블록에서 어떤 일이 발생하든 상관 없습니다. 블록에 return 문이 있으면 마지막으로 해당 return 문보다 먼저 실행됩니다.


Karthikeyan

네 그럴 겁니다. JVM 종료 또는 충돌이 아닌 경우에만


abhig

예, finally 블록은 항상 실행됩니다. 대부분의 개발자는 데이터베이스 연결, 결과 집합 개체, 명령문 개체를 닫는 이 블록을 사용하고 트랜잭션을 롤백하기 위해 Java 최대 절전 모드로 사용하기도 합니다.


Gautam Viradiya

@vibhash의 답변에 다른 답변을 추가하면 아래와 같은 변경 가능한 객체의 경우 어떤 일이 발생하는지 설명합니다.

 public static void main(String[] args) { System.out.println(test().toString()); } public static StringBuffer test() { StringBuffer s = new StringBuffer(); try { s.append("sb"); return s; } finally { s.append("updated "); } }

출력합니다

 sbupdated

Pradeep Kumaresan

나는 이것을 시도했다, 그것은 단일 스레드입니다.

 public static void main(String args[]) throws Exception { Object obj = new Object(); try { synchronized (obj) { obj.wait(); System.out.println("after wait()"); } } catch (Exception ignored) { } finally { System.out.println("finally"); } }

main Threadwait 상태에 있을 것이므로 finally 호출되지 않습니다 .

그래서 콘솔 출력이되지 않습니다 print String : 후 wait() 또는 finally

@Stephen C에 동의하여 위의 예는 여기에서 언급된 세 번째 사례 중 하나입니다.

다음 코드에서 이러한 무한 루프 가능성을 더 추가합니다.

 // import java.util.concurrent.Semaphore; public static void main(String[] args) { try { // Thread.sleep(Long.MAX_VALUE); // Thread.currentThread().join(); // new Semaphore(0).acquire(); // while (true){} System.out.println("after sleep join semaphore exit infinite while loop"); } catch (Exception ignored) { } finally { System.out.println("finally"); } }

사례 2: JVM이 먼저 충돌하는 경우

 import sun.misc.Unsafe; import java.lang.reflect.Field; public static void main(String args[]) { try { unsafeMethod(); //Runtime.getRuntime().halt(123); System.out.println("After Jvm Crash!"); } catch (Exception e) { } finally { System.out.println("finally"); } } private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); unsafe.putAddress(0, 0); }

참조: JVM을 어떻게 충돌시키나요?

사례 6: finally 블록이 데몬 Thread 의해 실행되고 다른 모든 데몬이 아닌 Threads finally 가 호출되기 전에 종료됩니다.

 public static void main(String args[]) { Runnable runnable = new Runnable() { @Override public void run() { try { printThreads("Daemon Thread printing"); // just to ensure this thread will live longer than main thread Thread.sleep(10000); } catch (Exception e) { } finally { System.out.println("finally"); } } }; Thread daemonThread = new Thread(runnable); daemonThread.setDaemon(Boolean.TRUE); daemonThread.setName("My Daemon Thread"); daemonThread.start(); printThreads("main Thread Printing"); } private static synchronized void printThreads(String str) { System.out.println(str); int threadCount = 0; Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); for (Thread t : threadSet) { if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) { System.out.println("Thread :" + t + ":" + "state:" + t.getState()); ++threadCount; } } System.out.println("Thread count started by Main thread:" + threadCount); System.out.println("-------------------------------------------------"); }

출력: "데몬 스레드"의 "최종 차단"이 실행되지 않았음을 의미하는 "최종"을 인쇄하지 않습니다.

 main Thread Printing Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED Thread :Thread[main,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:3 ------------------------------------------------- Daemon Thread printing Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:2 ------------------------------------------------- Process finished with exit code 0

dkb

다음 프로그램을 고려하십시오.

 public class SomeTest { private static StringBuilder sb = new StringBuilder(); public static void main(String args[]) { System.out.println(someString()); System.out.println("---AGAIN---"); System.out.println(someString()); System.out.println("---PRINT THE RESULT---"); System.out.println(sb.toString()); } private static String someString() { try { sb.append("-abc-"); return sb.toString(); } finally { sb.append("xyz"); } } }

Java 1.8.162부터 위의 코드 블록은 다음 출력을 제공합니다.

 -abc- ---AGAIN--- -abc-xyz-abc- ---PRINT THE RESULT--- -abc-xyz-abc-xyz

finally 를 사용하는 것이 다음 코드와 같은 좋은 방법임을 의미합니다.

 private static String someString() { StringBuilder sb = new StringBuilder(); try { sb.append("abc"); return sb.toString(); } finally { sb = null; // Just an example, but you can close streams or DB connections this way. } }

sam

finally x 의 (계산된) 값을 반환하기 전에 실행됩니다.

 System.out.println("x value from foo() = " + foo()); ... int foo() { int x = 2; try { return x++; } finally { System.out.println("x value in finally = " + x); } }

산출:

마지막으로 x 값 = 3
foo()의 x 값 = 2


hellzone

그것은 실제로 모든 언어에서 사실입니다... 마지막으로 반환이 메서드 본문의 어디에 있든 간에 항상 반환 문 전에 실행됩니다. 그렇지 않은 경우 finally 블록은 큰 의미가 없습니다.


Scott Dorman

try 블록에서 return을 최종적으로 교체할 때 return에 대한 요점 외에 예외도 마찬가지입니다. 예외를 throw하는 finally 블록은 try 블록 내에서 throw된 반환 또는 예외를 대체합니다.


Alex Miller

나는 다른 포럼에서 제공되는 모든 답변에 대해 매우 혼란스러워했고 마침내 코드를 작성하고 보기로 결정했습니다. 출력은 다음과 같습니다.

try 및 catch 블록에 return이 있더라도 finally가 실행됩니다.

 try { System.out.println("try"); return; //int i =5/0; //System.exit(0 ) ; } catch (Exception e) { System.out.println("catch"); return; //int i =5/0; //System.exit(0 ) ; } finally { System.out.println("Print me FINALLY"); }

산출

노력하다

마지막으로 나를 인쇄하십시오

  1. 위 코드의 try 및 catch 블록에서 return이 System.exit(0) 으로 대체되고 어떤 이유로든 그 전에 예외가 발생하는 경우.

milton

출처 : http:www.stackoverflow.com/questions/65035/does-a-finally-block-always-get-executed-in-java

반응형