programing

최종 블록은 항상 Java에서 실행되는가?

prostudy 2022. 4. 25. 21:30
반응형

최종 블록은 항상 Java에서 실행되는가?

이 코드를 고려해 볼 때, 내가 확실히 확신할 수 있을까?finally블록은 무슨 일이 있어도 항상 실행한다.something()그래?

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

finally사형 집행 후에 소집될 것이다.try또는catch암호 블록

유일한 시간finally다음과 같이 부르지 않을 것:

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

예제 코드:

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int test() {
    try {
        return 0;
    }
    finally {
        System.out.println("something is printed");
    }
}

출력:

something is printed. 
0

또한 나쁜 관행이지만, 최종 블록 내에 반환문이 있으면 일반 블록에서 다른 어떤 반환문도 능가할 것이다.즉, 다음 블록은 거짓으로 반환된다.

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

마지막 블록에서 예외를 두는 것도 마찬가지야.

자바 언어 명세서의 공식어는 다음과 같다.

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

A tryA로 진술하다.finally은 block은 를 먼저 된다.try그럼 선택권이 있다:

  • 시시의 try블록이 정상적으로 완료됨, [...]
  • 시시의 try블록이 갑자기 완료되는 이유는throwV의 [...]
  • 시시의 try다른 이유로 인해 블록이 갑자기 완료되고, 그 다음 R이finally블록이 실행되다그렇다면 다음과 같은 선택사항이 있다.
    • 최종 블록이 정상적으로 완료되면try이유 R 때문에 진술이 갑자기 완료된다.
    • 만약finally블록이 이유 S로 인해 갑자기 완료된 다음try사유 S(그리고 사유 R폐기됨) 때문에 진술이 갑자기 완료된다.

大社의 .return실제로 다음을 명시한다.

JLS 14.17 반환 성명

ReturnStatement:
     return Expression(opt) ;

A returnstatement이 은 진술이다.Expression 제어 권한을 메서드 또는 그것을 포함하는 생성자의 호출자에게 이전하려고 시도한다.

A return라고 진술하다.Expression 컨트롤을 포함하는 메소드의 호출자에게 제어 권한을 이전하려고 시도함; 값Expression메서드 호출의 가치가 된다.

앞의 설명은 단순히 "변속기 제어"가 아니라 "변속기 제어"가 있는 경우라고 한다.try다음을 포함하는 방법 또는 생성자 내의 문장try블록에는 다음이 포함된다.return진술, 그 다음엔 어떤 것이든finallytry제어권이 방법이나 생성자의 호출자에게 전달되기 전에 가장 안쪽에서 가장 바깥쪽으로 순서대로 문장이 실행될 것이다.갑작스러운 a 완료finally조항은 a에 의해 개시된 통제권의 이전을 방해할 수 있다.return명세서

다른 응답 외에도, '마침내'는 시도에서 예외/반환 값을 재정의할 권리가 있다는 점을 지적하는 것이 중요하다.막히다예를 들어, 다음 코드는 12를 반환한다.

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

마찬가지로 다음 방법으로는 예외를 두지 않는다.

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

다음과 같은 방법으로 던지지만:

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

약간의 수정으로 위의 예를 시도했다.

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블록이 실행되며 여기서 12가 지정i그 다음에System.out아웃이 실행되다

실행finally차단을 하다try블록은 12를 반환하지 않고 2를 반환한다. 왜냐하면 이 반환문이 다시 실행되지 않기 때문이다.

이 Eclipse를 에 이클립스를 실행한 후에 이클립스를 디버깅할 수 수 .System.outfinally차단을 하다return…의 성명try블록이 다시 실행된다.그러나 이것은 사실이 아니다.단순히 값 2를 돌려준다.

여기 케빈의 대답에 대한 자세한 설명이 있다.반환할 표현을 미리 평가해 두는 것이 중요하다.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

그것이 마침내 한 블록의 전체 아이디어다.그것은 당신이 다른 무엇보다도 당연히 돌아오기 때문에 건너뛸 수도 있는 청소를 확실히 하도록 해준다.

마지막으로 시도 블록에서 발생하는 작업에 관계없이 호출됨(호출하지 않는 경우)System.exit(int)또는 다른 이유로 Java Virtual Machine이 출시됨).

이에 대해 논리적으로 생각할 수 있는 방법은 다음과 같다.

  1. 최종 블록에 배치된 코드는 시도 블록 내에서 발생하는 모든 을 실행해야 한다.
  2. 따라서 시도 블록의 코드가 값을 반환하거나 예외를 발생시키려 할 경우, 최종 블록이 실행될 수 있을 때까지 항목은 '선반에' 배치된다.
  3. 왜냐하면 최종 블록의 코드는 (정의상) 높은 우선순위를 가지고 있기 때문에 그것은 반환하거나 원하는 것을 던질 수 있다.이 경우 '선반 위에' 남겨진 것은 모두 폐기된다.
  4. 이에 대한 유일한 예외는 '시스템'에서와 같이 시도 블록 중에 VM이 완전히 종료되는 경우 입니다.퇴장'

마지막으로 System.exit(0..)를 호출하는 것과 같은 비정상적인 프로그램 종료가 없는 한 항상 실행되므로 시스템sout이 인쇄될 것이다.

아니, 항상 예외적인 케이스가 하나 있는 것은 아니다./ System.exit(0); 최종 블록 이전에 최종 실행이 방지된다.

  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

이나 JVM과의 한 System.exit(0).

또한 최종 블록 내에서 반환되는 모든 값은 최종 블록 실행 전에 반환된 값을 재정의하므로, 최종적으로 Try를 사용할 때 모든 출구 지점을 확인하는 데 주의하십시오.

마지막으로 항상 실행이 중요한데, 단지 반환 후 코드에 나타난다고 해서 그것이 그렇게 구현되는 것은 아니다.Java 런타임은 종료 시 이 코드를 실행할 책임이 있다.try막다

예를 들어 다음과 같은 경우:

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

런타임은 다음과 같은 것을 생성한다.

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

검색되지 않은 예외가 발생할 경우finally블록이 실행되며 예외가 계속 전파된다.

네, 전화 받을 겁니다.그것이 드디어 키워드를 갖는 요점이다.try/catch 블록에서 뛰어내리는 경우, 최종 블록을 건너뛸 수 있는 경우, System.out.println을 try/catch 외부에 놓는 것과 동일하다.

왜냐하면 전화를 걸지 않으면 항상 블록이 호출되기 때문이다.System.exit()(또는 나사산이 충돌함).

공식 자바 문서(여기를 클릭)에 간결하게 다음과 같이 기록된다.

시도 또는 캐치 코드가 실행되는 동안 JVM이 종료되면 최종 블록이 실행되지 않을 수 있다.마찬가지로, 시도나 캐치 코드를 실행하는 스레드가 중단되거나 소멸되는 경우, 응용 프로그램 전체가 계속되어도 최종 블록은 실행되지 않을 수 있다.

당신이 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

항상은 아냐.

는 자바 언어 은 어어 게게를 하고 있다.try-catch-finally그리고try-catch블록은 14.20.2에서 작동한다.
어떤 장소에서도, 그것은 다음을 명시되지 않았다.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는 CODE 이후 FIN이 실행된다는 것을 보증하지 않는다.JLS는 CODENEXT가 실행되면 항상 CODE 다음에 그리고 NEXT 전에 FIN이 실행된다는 것을 보장한다.

왜 JLS는 그 사실을 보증하지 않는가.finally블록은 항상 다음에 실행된다.try차단? 왜냐하면 불가능하기 때문이다.JVM이 완료 직후 중단(킬, 충돌, 전원 꺼짐)될 가능성은 낮지만 가능성이 있다.try를 실행하기 전에 차단하다.finallyJLS가 피할 수 있는 건 아무것도 없어

따라서, 적절한 행동에 대한 모든 소프트웨어는finally블록 다음에 항상 실행되는 블록try완전한 블록은 도청되고 있다.

return의 지령try블록은 이 문제와 무관하다.실행 후 코드에 도달하는 경우try-catch-finally는 것이 보증되어 있다finally블록은 이전과 함께 또는 이전 없이 실행되었을 것이다.return 사항try막다

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

출력:

값 최종 = 값 최종 = 3
x= 2foo() = 2의 x 값

네, 그럴 거예요.달리 System.exit()가 호출되거나 JVM이 충돌하지 않는 한, 당신의 시도나 캐치 블록에서 무슨 일이 일어나든 간에, 만약 블록에 반환문이 있다면, 그 반환문 전에 최종적으로 실행될 것이다.

네, 그럴 거예요.JVM이 종료되거나 충돌하지 않는 경우에만 해당

예, 마지막으로 블록은 항상 실행된다.대부분의 개발자는 이 블록을 사용하여 데이터베이스 연결, 결과 집합 개체, 문 개체를 닫을 수 있으며 트랜잭션을 롤백하기 위해 자바 최대 절전 모드로 사용할 수도 있다.

finally실행될 것이고 그것은 확실하다.

finally다음과 같은 경우 실행되지 않음:

사례 1 :

실할할 때를 할 때System.exit().

사례 2 :

JVM/스레드가 충돌하는 경우.

사례 3:

실행이 수동으로 중지된 경우.

@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영원히 진술하고, 따라서 절대 부르지 않을 이다.

따라서 콘솔 출력이 작동하지 않음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);
}

Ref: 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.
    }
}

사실 그건 어느 언어에서나 맞는 말이야...최종적으로, 그 반환이 메소드 본문에 어디에 있든지 간에, 반환문명 전에 항상 실행될 것이다.만약 그렇지 않았다면, 마침내 블록은 큰 의미를 갖지 못했을 것이다.

try block에서 return을 최종적으로 대체하는 반환점에 추가하여 예외도 마찬가지다.마지막으로 예외를 발생시키는 블록은 시도 블록 내에서 발생하는 반환 또는 예외를 대체한다.

참조URL: https://stackoverflow.com/questions/65035/does-a-finally-block-always-get-executed-in-java

반응형