2035

이 코드를 고려하면절대적으로 확실한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.");
}


  • 직접 테스트 한 후에도너의Java / JVM의 구현 또는 버전이 수행 할 것이며 코드가 무엇인지 알 수 없습니다할까요(표준에 따라) 할 것이므로 질문은 여전히 유효합니다. 여러 가지 답변 중에서 이러한 측면을 해결하게되어 기쁘게 생각합니다. - Rhubbarb
  • 아니항상 - Boann
  • 유효 자바가 다르게 말한다.informit.com/articles/article.aspx?p=1216151&seqNum=7 - Binoy Babu
  • @BinoyBabu,파이널 라이저! =finally;파이널 라이저==finalize()방법. - jaco0646
  • @LordFarquaad ;-) 그것은 항상 보장됩니다. - MC Emperor

30 답변


2267

예,finallytry 또는 catch 코드 블록 실행 후 호출됩니다.

유일한 시간들finally부르지 않을 것이다 :

  1. 호출하는 경우System.exit();
  2. JVM이 먼저 충돌하면;
  3. JVM이 무한 루프 (또는 중단되지 않는 다른 종료 문)에 도달하면try또는catch블록;
  4. OS가 강제로 JVM 프로세스를 종료하면; 예 : 유닉스에서 "kill -9".
  5. 호스트 시스템이 종료되면; 예 : 전원 오류, 하드웨어 오류, OS 패닉 등이 있습니다.
  6. finally 블록이 데몬 스레드에 의해 실행되고 다른 모든 비 데몬 스레드가 마침내 호출되기 전에 종료되는 경우.


  • 사실은thread.stop()반드시 예방하지는 않는다.finally실행을 차단하십시오. - Piotr Findeisen
  • 어때요?finally블록이 호출됩니다.그만큼try블록 및전에제어는 다음 명령문으로 전달됩니다. 그것은 무한 루프를 포함하는 try 블록과 일관되게 결국 finally 블록이 실제로 호출되지 않는다는 것과 일치합니다. - Andrzej Doyle
  • 또 다른 경우가 있습니다. 우리는 중첩 된try-catch-finally블록들 - ruhungry
  • 또한, finally 블록은 데몬 스레드에 의해 던져진 예외의 경우에 호출되지 않습니다. - Amrish Pandey
  • @BinoyBabu - 파이널 라이저에 관한 내용으로, 최종적으로 차단하지는 않습니다. - avmohan

472

예제 코드 :

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


  • 참고 자료 : C #에서는 동작이 동일하다는 점을 제외하고는finally~와 함께 절return 2;허용되지 않습니다 (컴파일러 오류). - Alexander Pacha
  • 알고 있어야 할 중요한 세부 사항은 다음과 같습니다.stackoverflow.com/a/20363941/2684342 - WoodenKitty
  • finally 블록 자체에 return 문을 추가 할 수도 있습니다. 그러면 finally 블록이 이전 반환 값을 재정의합니다. 이것은 또한 처리되지 않은 예외를 마법처럼 버립니다. 이때 코드 리팩터링을 고려해야합니다. - Zyl
  • 결국 트럼프가 돌아 오는지 실제로 증명되지는 않습니다. 반환 값은 호출자 코드에서 인쇄됩니다. 그다지 증명할 수없는 것 같습니다. - Trimtab
  • 미안 해요,하지만 이건 증거가 아니라 데모예요. 이 예제가 항상 모든 Java 플랫폼에서이 방식으로 작동하고 유사한 예제도 항상 이와 같은 방식으로 작동한다는 것을 보여줄 수 있다면 이는 단지 하나의 증거 일뿐입니다. - Stephen C

339

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

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

finally 블록에서 예외를 던지는 것과 같은 일입니다.


  • 이것은 정말로 나쁜 습관입니다. 만나다stackoverflow.com/questions/48088/…나쁜 이유에 대한 자세한 정보는 - John Meagher
  • 동의했다. finally {} 내의 return은 try {}에서 throw 된 모든 예외를 무시합니다. 무서운! - neu242
  • @ dominicbri7 왜 더 나은 방법이라고 생각합니까? 그리고 함수 / 메소드가 무효 일 때 왜 다른가? - corsiKa
  • 같은 이유로 나는 결코 C ++ 코드에서 goto를 사용하지 않는다. 다중 반환은 읽기가 어렵고 디버그하기 어렵게 만든다고 생각합니다 (물론 간단한 경우에는 적용 할 수 없습니다). 제 생각에는 그냥 개인적으로 선호하는 것이고 결국에는 두 가지 방법 중 하나를 사용하여 동일한 것을 얻을 수 있습니다. - dominicbri7
  • 어떤 종류의 예외적 인 경우가 발생하면 많은 수익을 사용하는 경향이 있습니다. 마치 (계속하지 않을 이유가있는 경우) 복귀; - iHearGeoff

237

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

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

에이try성명서finally블록은 먼저try블록. 그런 다음 선택이 있습니다.

  • 실행의 경우try블록이 정상적으로 완료되면 [...]
  • 실행의 경우try블록은 갑자기throw값의V, [...]
  • 실행의 경우try다른 이유로 블록이 갑자기 완료됩니다.아르 자형, 그 다음에finally블록이 실행됩니다. 그런 다음 선택이 있습니다.
    • finally 블록이 정상적으로 완료되면try이유문으로 진술이 갑자기 완료된다.아르 자형.
    • 만약finally블록이 이유 때문에 갑자기 완료된다.에스, 그 다음에try이유문으로 진술이 갑자기 완료된다.에스(이유아르 자형버려진).

에 대한 사양return사실이 사실을 명시 적으로 나타냅니다.

JLS 14.17 신고서

ReturnStatement:
     return Expression(opt) ;

에이return성명서가없는 성명서Expression 시도컨트롤을 포함하는 메서드 또는 생성자의 호출자에게 제어권을 넘깁니다.

에이return성명서Expression 시도그것을 포함하는 메소드의 호출자에게 제어권을 넘깁니다. 의 가치Expression메소드 호출의 값이됩니다.

앞의 설명은 "시도컨트롤을 전송하는"단지"통제를 이전하다"왜냐하면 만약에try메소드 또는 생성자 내의 명령문try블록에는return문 다음에 어떤finally그 조항들try명령문은 메서드 나 생성자의 호출자에게 제어가 전달되기 전에 가장 안쪽에서 가장 바깥쪽으로 순서대로 실행됩니다. 갑작스럽게finally절은 a에 의해 시작된 제어 전송을 방해 할 수 있습니다.return성명서.


142

다른 응답들에 덧붙여, '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();
    }
}


  • 중간 케이스는 finally 블록 안에 return 문을 갖는 것이 절대적으로 끔찍한 이유입니다 (Throwable을 숨길 수 있음). - Dimitris Andreou

97

나는 약간의 변경으로 위의 예제를 시도했다.

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를가집니다.finally12가 할당 된 블록이 실행됩니다.i그리고System.out아웃이 실행됩니다.

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

Eclipse에서이 코드를 디버깅 할 경우 실행 후System.outfinally블록하다return성명서try블록이 다시 실행됩니다. 그러나 이것은 사실이 아닙니다. 단순히 값 2를 반환합니다.


  • 이 예제는 대단합니다. 마지막으로 수십 개의 스레드에서 언급되지 않은 것을 추가합니다. 나는 거의 모든 개발자가이 사실을 알게 될 것이라고 생각한다. - HopefullyHelpful
  • 만약i원시 객체가 아니라 Integer 객체입니다. - Yamcha
  • 이 사건을 이해하는 데 어려움을 겪고 있습니다.docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.17"표현식을 가진 return 문은 그것을 포함하는 메서드 또는 lambda 몸체의 호출자에게 제어를 전달하려고 시도한다. ... 표현식의 평가가 정상적으로 완료되면 값 V를 생성한다"는 것을 말한다. 이 문장에서 추측 할 수있는 것은 - 반환 값이 V 값을 평가하면 반환 값을 다시 평가하지 않아 반환 값에 영향을 미치지 않아 수정되었음을 나타냅니다. - meexplorer
  • 그러나 이것에 관한 어떤 증거도 찾지 못했습니다. 반환하지 않으면 표현을 다시 평가할 수 없습니다. - meexplorer
  • @meexplorer 조금 늦었지만 설명되어 있습니다.JLS 14.20.2. try-finally 및 try-catch-finally 실행- 조금 복잡하게 말했어.14.17. return 문읽어야한다. - Carlos Heuberger

89

여기에케빈의 대답. 반환되는 표현식이 이전에 평가된다는 것을 아는 것이 중요합니다.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



48

그것이 결국 블록의 전체 아이디어입니다. 물론, 다른 것들 중에서 돌아 오기 때문에 건너 뛸 수있는 정리 작업을 수행 할 수 있습니다.

마침내 불러옵니다.관계없이try 블록에서 (~ 않는 한너는 부른다.System.exit(int)또는 Java 가상 머신이 다른 이유로 착수 한 경우).


33

이것을 생각해 볼 수있는 논리적 인 방법은 다음과 같습니다.

  1. finally 블록에 배치 된 코드는 실행해야합니다.어떤 일이 일어나든지try 블록 내에서
  2. 따라서 try 블록의 코드가 값을 반환하거나 예외를 throw하려고하면 finally 블록이 실행할 수있을 때까지 항목이 '선반에 놓입니다.'
  3. finally 블록의 코드는 (정의상) 우선 순위가 높기 때문에 원하는대로 반환하거나 던질 수 있습니다. 이 경우 '선반에 놓아 둔'것은 버려집니다.
  4. 유일한 예외는 try 블록에서 VM이 완전히 종료 된 경우입니다. 'System.exit'에 의해


  • 이것은 단지 & quot; 그것에 대해 생각할 논리적 인 방법입니다 & quot; 또는 finally 블록이 사양에 따라 작동하도록 의도 된 것입니까? Sun 자원에 대한 링크는 여기에서 매우 흥미로울 것입니다. - matias

16

또한 마침내 돌아와서 예외를 버릴 것입니다.http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


15

마지막으로 System.exit (0) 호출과 같은 비정상적인 프로그램 종료가 발생하지 않는 한 항상 실행됩니다. 따라서, sysout이 인쇄됩니다.


15

아니, 예외적 인 경우는 하나도 없습니다 // System.exit (0); 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");
        }
    }
}


  • 그리고 System.exit ()을 절대 호출해서는 안되는 이유 중 하나가 ... - Franz D.

14

finally 블록은 JVM 충돌이나 호출로 인해 비정상적인 프로그램 종료가 발생하지 않는 한 항상 실행됩니다.System.exit(0).

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


8

마지막으로 항상 실행됩니다. 모든 요소가 반환 된 후에 코드에 나타나기 때문에 구현 방법을 나타내는 것은 아닙니다. 자바 런타임은 코드를 종료 할 때이 코드를 실행할 책임이 있습니다.try블록.

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

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

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

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

캐치되지 않는 예외가 Throw되면finally블록이 실행되고 예외가 전파됩니다.


8

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

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


7

finally 블록은 호출하지 않으면 항상 호출되기 때문에System.exit()(또는 스레드가 충돌합니다).


7

간략하게, 공식 자바 문서 (Click이리), 그것은 쓰여진다 -

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


7

대답은 간단하다..

입력:

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


  • 대답은 간단합니다. - Christophe Roussy
  • @ChristopheRoussy 어떻게? 설명해 주시겠습니까? - Meet
  • 대답을 읽으면 원래 질문은 & # 39; 항상 실행됩니까? & # 39; 항상 그렇지는 않습니다. 귀하의 경우 그것은 원래의 질문에 답하지 않고 오해의 소지가있는 초보자 일 수도 있습니다. - Christophe Roussy
  • 그럼 어떤 경우에는 실행되지 않을까요? - Meet
  • 다른 답변에 언급 된 모든 경우에 1000 + upvotes의 허용 된 답변을 참조하십시오. - Christophe Roussy

6

예, 전화가 걸립니다. finally 키워드를 사용하는 것이 중요합니다. try / catch 블록에서 점프하여 finally 블록을 건너 뛸 수 있다면 System.out.println을 try / catch 외부에 둡니다.


6

예, 그렇게 될 것입니다. try 또는 catch 블록에서 System.exit ()이 호출되거나 JVM이 충돌하지 않는 한 아무 일도 일어나지 않습니다. 블록에 return 문이 있으면 해당 return 문보다 먼저 finally 문이 실행됩니다.


6

예, 가능합니다. JVM 종료 또는 충돌이 발생하지 않는 경우에만


6

예. 블록은 항상 실행됩니다. 대부분의 개발자는이 블록을 사용하여 데이터베이스 연결, 결과 집합 개체, 명령문 개체를 닫고 Java 하이버 네이트를 사용하여 트랜잭션을 롤백합니다.


5

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

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

    private static String someString() {

        try {
            sb.append("-abc-");
            return sb.toString();

        } finally {
            sb.append("xyz");
        }
    }
}

Java 1.8.162부터 위의 코드 블록은 다음과 같은 결과를 제공합니다.

-abc-
---AGAIN---
-abc-xyz-abc-

즉,finally객체를 해제하는 것은 다음 코드와 같은 좋은 습관입니다.

private static String someString() {

    StringBuilder sb = new StringBuilder();

    try {
        sb.append("abc");
        return sb.toString();

    } finally {
        sb = null;
    }
}


  • 그것이 될 수 없다.sb.setLength(0)마침내? - user7294900
  • sb.setLength (0)는 StringBuffer의 데이터를 비 웁니다. 따라서 sb = null은 객체를 참조에서 분리합니다. - Samim

4

그것은 실제로 어떤 언어에서나 사실입니다 ... 마침내 return 문 앞에 항상 실행됩니다. 리턴은 메소드 본문에 상관없이 항상 실행됩니다. 그것이 사실이 아니라면, finally 블록은별로 의미가 없을 것입니다.


  • 모든 언어가 가진 것은 아닙니다.finally처음에는 ... - glglgl

4

결승전은 당신이 가진 어떤 경우에도 항상 호출되기 때문에. 당신은 예외가 없으며, 여전히 호출되고, 예외를 잡아냅니다. 여전히 호출됩니다.


4

정상적인 실행 과정에서 이것을 고려하십시오. 즉, 예외가 throw되지 않습니다. 메소드가 '무효'가 아니라면 항상 명시 적으로 무언가를 반환하지만 마침내 항상 실행됩니다.


4

예외가 발생하면 마지막으로 실행됩니다. 예외가 throw되지 않으면 마지막으로 실행됩니다. 예외가 잡히면 마침내 실행됩니다. 예외가 잡히지 않으면 마지막으로 실행됩니다.

JVM이 종료 될 때까지만 실행되지 않습니다.


4

마지막으로 블록은 항상 예외 처리 여부를 실행합니다. try 블록 전에 예외가 발생하면 finally 블록이 실행되지 않습니다.


4

finally실행하고 그것은 확실히입니다.

finally다음과 같은 경우에는 실행되지 않습니다.

사례 1 :

실행 중일 때System.exit().

사례 2 :

JVM / 스레드가 충돌 할 때.

사례 3 :

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



4

예, 왜냐하면통제 문 없음예방할 수있다.finally실행에서.

다음은 모든 코드 블록이 실행되는 참조 예입니다.

| x | Current result | Code 
|---|----------------|------ - - -
|   |                |     
|   |                | public static int finallyTest() {
| 3 |                |     int x = 3;
|   |                |     try {
|   |                |        try {
| 4 |                |             x++;
| 4 | return 4       |             return x;
|   |                |         } finally {
| 3 |                |             x--;
| 3 | throw          |             throw new RuntimeException("Ahh!");
|   |                |         }
|   |                |     } catch (RuntimeException e) {
| 4 | return 4       |         return ++x;
|   |                |     } finally {
| 3 |                |         x--;
|   |                |     }
|   |                | }
|   |                |
|---|----------------|------ - - -
|   | Result: 4      |

아래의 변형에서,return x;건너 뛸 것입니다. 결과는 여전히있다.4:

public static int finallyTest() {
    int x = 3;
    try {
        try {
            x++;
            if (true) throw new RuntimeException("Ahh!");
            return x; // skipped
        } finally {
            x--;
        }
    } catch (RuntimeException e) {
        return ++x;
    } finally {
        x--;
    }
}

참고 문헌은 물론 그들의 상태를 추적합니다. 이 예제는value = 4:

static class IntRef { public int value; }
public static IntRef finallyTest() {
    IntRef x = new IntRef();
    x.value = 3;
    try {
        return x;
    } finally {
        x.value++; // will be tracked even after return
    }
}

연결된 질문


관련된 질문

최근 질문