이 코드를 고려할 때 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"); }
질문자 :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
으로 호출되지 않는 유일한 경우는 다음과 같습니다.
System.exit()
를 호출하면Runtime.getRuntime().halt(exitStatus)
를 호출하면try
또는 catch
블록에서 무한 루프(또는 다른 인터럽트 불가능하고 종료되지 않는 문)에 도달하는 경우kill -9 <pid>
finally
블록이 데몬 스레드에 의해 실행되고 다른 모든 비 데몬 스레드가 finally
예제 코드:
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
또한 나쁜 습관이지만 finally 블록 내에 return 문이 있으면 일반 블록의 다른 반환보다 우선합니다. 즉, 다음 블록은 false를 반환합니다.
try { return true; } finally { return false; }
finally 블록에서 예외를 던질 때도 마찬가지입니다.
다음은 Java 언어 사양의 공식 단어입니다.
14.20.2. try-finally 및 try-catch-finally 실행
finally
블록이 있는try
문try
블록을 실행하여 실행됩니다. 그런 다음 선택이 있습니다.
try
블록의 실행이 정상적으로 완료되면 [...]- V 값
throw
try
블록의 실행이 갑자기 완료되면 [...]try
블록의 실행이 다른 이유로 R 갑자기 완료되면finally
블록이 실행됩니다. 그런 다음 선택이 있습니다.
- finally 블록이 정상적으로 완료되면 이유 R
try
문이 갑자기 완료됩니다.finally
블록이 이유 S 로 인해 갑자기 완료되면try
문이 S 이유 때문에 갑자기 완료 되고 이유 R 은 폐기됩니다 .
return
대한 사양은 실제로 이것을 명시적으로 만듭니다.
ReturnStatement: return Expression(opt) ;
Expression
이 없는return
문은 제어를 포함하는 메서드 또는 생성자의 호출자에게 제어를 전송 하려고 시도합니다.
Expression
있는return
문은 컨트롤을 포함하는 메서드의 호출자에게 제어를 전송 하려고 시도합니다.Expression
의 값은 메소드 호출의 값이 됩니다.위의 설명은 어떤이있는 경우 때문에 그냥 "전송 제어"보다는 "전송 제어에 시도"라고
try
방법 또는 생성자 내에서 문try
를 차단 포함return
문 후 어떤,finally
사람들의 조항try
문에서 실행됩니다 제어가 메서드 또는 생성자의 호출자에게 전달되기 전에 가장 안쪽에서 바깥쪽으로 순서입니다.finally
절이 갑자기 완료되면return
문에 의해 시작된 제어 전송이 중단될 수 있습니다.
다른 응답 외에도 '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(); } }
다음은 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
약간 수정하여 위의 예를 시도했습니다.
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.out
을 try
return
문이 다시 실행된다는 느낌을 받게 됩니다. 그러나 이것은 사실이 아닙니다. 단순히 값 2를 반환합니다.
이것이 finally 블록의 전체 아이디어입니다. 물론 돌아가기 때문에 건너뛸 수 있는 정리 작업을 확실히 수행할 수 있습니다.
마지막으로 try 블록에서 발생하는 일 에 관계없이 호출됩니다( System.exit(int)
를 호출하거나 다른 이유로 Java Virtual Machine이 종료 되지 않는 한).
이에 대해 논리적으로 생각하는 방법은 다음과 같습니다.
finally는 비정상적인 프로그램 종료가 없는 한 항상 실행됩니다(예: System.exit(0).. 호출). 따라서 sysout이 인쇄됩니다.
아니요, 항상 한 가지 예외가 있는 것은 아닙니다. // 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"); } } }
또한 최종적으로 반환하면 모든 예외가 발생합니다.http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
System.exit(0)
호출로 인해 비정상적인 프로그램 종료가 발생하지 않는 한 항상 실행됩니다.
게다가 finally 블록 내에서 반환된 모든 값은 finally 블록을 실행하기 전에 반환된 값을 무시하므로 try finally를 사용할 때 모든 종료점을 확인하는 데 주의해야 합니다.
마지막으로 항상 실행된다는 것이 요점입니다. 반환 후 코드에 표시된다고 해서 그렇게 구현되는 것은 아닙니다. try
블록을 종료할 때 이 코드를 실행할 책임이 있습니다.
예를 들어 다음이 있는 경우:
int foo() { try { return 42; } finally { System.out.println("done"); } }
런타임은 다음과 같은 것을 생성할 것입니다:
int foo() { int ret = 42; System.out.println("done"); return 42; }
잡히지 않은 예외가 발생하면 finally
블록이 실행되고 예외는 계속 전파됩니다.
네, 호출됩니다. 이것이 finally 키워드를 갖는 요점입니다. try/catch 블록 밖으로 점프하는 것이 finally 블록을 건너뛸 수 있다면 이는 System.out.println을 try/catch 외부에 두는 것과 같습니다.
System.exit()
를 호출하지 않는 한(또는 스레드가 충돌하지 않는 한) 항상 호출되기 때문입니다.
이는 i 값을 12로 할당했지만 i 값을 함수에 반환하지 않았기 때문입니다. 올바른 코드는 다음과 같습니다.
public static int test() { int i = 0; try { return i; } finally { i = 12; System.out.println("finally trumps return."); return i; } }
대답은 간단 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
간결하게, 공식 Java 문서(여기를 클릭하십시오)에는 다음과 같이 쓰여 있습니다.
try 또는 catch 코드가 실행되는 동안 JVM이 종료되면 finally 블록이 실행되지 않을 수 있습니다. 마찬가지로 try 또는 catch 코드를 실행하는 스레드가 중단되거나 종료되면 응용 프로그램이 전체적으로 계속되더라도 finally 블록이 실행되지 않을 수 있습니다.
Java 언어 사양 try
- catch
- finally
및 try
- catch
블록이 작동하는 방식을 설명합니다.
finally
블록이 항상 실행되도록 지정하지 않습니다. try
- catch
- finally
및 try
- 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는 CODE 및 NEXT 가 실행되는 경우 FIN 이 항상 CODE 이후 및 NEXT 이전에 실행되도록 보장합니다.
finally
블록이 항상 try
블록 다음에 실행되도록 보장하지 않는 이유는 무엇입니까? 불가능하기 때문입니다. try
finally
블록을 실행하기 전에 JVM이 중단(종료, 충돌, 전원 끄기)될 가능성은 거의 없습니다. 이를 피하기 위해 JLS가 할 수 있는 일은 없습니다.
따라서 적절한 동작 try
블록이 완료된 후 항상 실행되는 finally
블록에 의존하는 소프트웨어는 버그가 있습니다.
try
return
명령은 이 문제와 관련이 없습니다. 실행은 후 코드에 도달하면 try
- catch
- finally
이 보장되어있는 것을 finally
블록으로 사용하거나 사용하지 않고, 이전에 실행 된 것입니다 return
내부 지침 try
차단합니다.
네, 그럴 것입니다. 그렇지 않으면 System.exit()가 호출되거나 JVM이 충돌하지 않는 한 try 또는 catch 블록에서 어떤 일이 발생하든 상관 없습니다. 블록에 return 문이 있으면 마지막으로 해당 return 문보다 먼저 실행됩니다.
네 그럴 겁니다. JVM 종료 또는 충돌이 아닌 경우에만
예, finally 블록은 항상 실행됩니다. 대부분의 개발자는 데이터베이스 연결, 결과 집합 개체, 명령문 개체를 닫는 이 블록을 사용하고 트랜잭션을 롤백하기 위해 Java 최대 절전 모드로 사용하기도 합니다.
@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
나는 이것을 시도했다, 그것은 단일 스레드입니다.
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
Thread
는 wait
상태에 있을 것이므로 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
다음 프로그램을 고려하십시오.
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. } }
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
그것은 실제로 모든 언어에서 사실입니다... 마지막으로 반환이 메서드 본문의 어디에 있든 간에 항상 반환 문 전에 실행됩니다. 그렇지 않은 경우 finally 블록은 큰 의미가 없습니다.
try 블록에서 return을 최종적으로 교체할 때 return에 대한 요점 외에 예외도 마찬가지입니다. 예외를 throw하는 finally 블록은 try 블록 내에서 throw된 반환 또는 예외를 대체합니다.
나는 다른 포럼에서 제공되는 모든 답변에 대해 매우 혼란스러워했고 마침내 코드를 작성하고 보기로 결정했습니다. 출력은 다음과 같습니다.
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"); }
산출
노력하다
마지막으로 나를 인쇄하십시오
System.exit(0)
으로 대체되고 어떤 이유로든 그 전에 예외가 발생하는 경우.출처 : http:www.stackoverflow.com/questions/65035/does-a-finally-block-always-get-executed-in-java
환경 변수 값에 액세스하는 방법 (0) | 2021.11.13 |
---|---|
macOS 업데이트 후 Git이 작동하지 않음(xcrun: 오류: 잘못된 활성 개발자 경로(/Library/Developer/CommandLineTools) (0) | 2021.11.13 |
Git fetch 원격 브랜치 (0) | 2021.11.13 |
데이터베이스 인덱싱은 어떻게 작동합니까? [닫은] (0) | 2021.11.13 |
문자열을 float 또는 int로 구문 분석하는 방법은 무엇입니까? (0) | 2021.11.13 |