Hat ein schließlich bekommen Block immer in Java ausgeführt?
-
09-06-2019 - |
Frage
In Anbetracht dieser Code, kann ich sein absolut sicher , dass der finally
Block führt immer, egal was something()
ist?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
Lösung
Ja, finally
wird nach der Ausführung der try
oder catch
Codeblöcke aufgerufen werden.
Das einzige Mal finally
wird nicht aufgerufen werden:
- Wenn Sie rufen
System.exit()
- Wenn die JVM stürzt erste
- Wenn die JVM erreichen eine Endlosschleife (oder ein anderer nicht-unterbrechbare, nicht abbreche statement) im
try
odercatch
Block - Wenn das Betriebssystem gewaltsam den JVM-Prozess endet; z.B.
kill -9 <pid>
auf UNIX - Wenn das Host-System stirbt; beispielsweise Stromausfall, Hardware-Fehler, O Panik, et cetera
- Wenn der
finally
Block wird von einem Dämon-Thread und alle anderen Nicht-Daemon-Threads Ausgang ausgeführt werden, bevorfinally
genannt wird
Andere Tipps
Beispielcode:
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.");
}
}
Ausgabe:
finally trumps return.
0
Auch, obwohl es schlechte Praxis, wenn es eine return-Anweisung innerhalb des finally-Block ist, wird es Trumpf andere Rückkehr aus dem regulären Block. Das heißt, der folgende Block würde return false:
try { return true; } finally { return false; }
Das Gleiche gilt für das Werfen Ausnahme von der finally-Block.
Hier sind die offiziellen Worte aus der Java Language Specification.
14.20.2. Durchführung von Versuchen-finally und try-catch-finally
Eine
try
Anweisung mit einemfinally
Block wird durch erste Ausführung destry
Block ausgeführt. Dann gibt es eine Auswahl:
- Wenn die Ausführung des
try
Block schließt normalerweise, [...]- Wenn die Ausführung des
try
Block wegen einesthrow
eines Wertes abrupt beendet V [...]- Wenn die Ausführung des
try
Block abrupt aus einem anderen Grund beendet R , dann wird derfinally
Block ausgeführt. Dann gibt es eine Auswahl:
- Wenn der finally-Block normal abgeschlossen ist, dann wird die
try
Anweisung abgeschlossen abrupt Grund R .- Wenn der
finally
Block abrupt Grund beendet S , dann schließt dietry
Anweisung abrupt Grund S ( und Vernunft R verworfen ).
Die Spezifikation für return
tatsächlich macht dies deutlich:
JLS 14.17 Die return-Anweisung
ReturnStatement: return Expression(opt) ;
A
return
Anweisung ohneExpression
Versuche die Steuerung an den Aufrufer des Verfahrens oder den Konstruktor zu übertragen, die sie enthält.A
return
Anweisung mit einerExpression
Versuche die Steuerung an den Aufrufer der Methode zu übertragen, die sie enthält; der Wert derExpression
den Wert des Methodenaufrufes wird.Die vorstehenden Beschreibungen sagen " Versuche Kontrolle übertragen " und nicht nur " wechselt die Steuerung ", weil, wenn es irgendwelche
try
Aussagen innerhalb der Methode oder deren Konstruktortry
blockiert diereturn
Anweisung enthalten, dann werden alle Klauselnfinally
diesertry
Anweisungen ausgeführt werden, um die innerste, zu den äußersten, bevor die Steuerung an den Aufrufer des Verfahrens oder der Konstruktor übertragen wird. Abrupte Abschluss einerfinally
-Klausel kann die Übertragung der Kontrolle unterbricht durch einereturn
Anweisung eingeleitet.
Zusätzlich zu den anderen Antworten, ist es wichtig, darauf hinzuweisen, dass ‚endlich‘ das Recht hat, jede Ausnahme / Rückgabewert vom try..catch Block außer Kraft zu setzen. Zum Beispiel kann der folgende Code gibt 12:
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
In ähnlicher Weise kann das folgende Verfahren nicht eine Ausnahme:
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
Während die folgende Methode es nicht werfen:
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
Ich habe versucht, das obige Beispiel mit geringfügiger Änderung -
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.");
}
}
Die oben genannten Code-Ausgänge:
schließlich Trümpfe Rückkehr.
2
Dies liegt daran, wenn return i;
ausgeführt i
einen Wert hat, 2. Danach wird der finally
Block ausgeführt wird, in dem 12 zugeordnet ist i
und dann System.out
aus ausgeführt wird.
Nach dem Ausführen des finally
blockiert den try
Block 2 zurück, anstatt 12 zurückkehrt, weil diese Anweisung return wieder nicht ausgeführt wird.
Wenn Sie diesen Code in Eclipse debuggen werden dann werden Sie ein Gefühl bekommen, dass System.out
von finally
Block der return
Anweisung von try
Block nach der Ausführung wieder ausgeführt wird. Aber dies ist nicht der Fall. Es gibt einfach den Wert 2.
Hier ist eine Ausarbeitung von Kevins Antwort . Es ist wichtig zu wissen, dass der Ausdruck zurückgegeben werden, bevor finally
ausgewertet wird, auch wenn es nach zurückgeführt wird.
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");
}
}
Ausgabe:
X
finally trumps return... sort of
0
Das ist die ganze Idee eines schließlich blockieren. Damit können Sie sicherstellen, dass Sie tun Bereinigungen, die sonst übersprungen werden könnten, weil Sie zurückkommen, unter anderem natürlich.
Schließlich wird aufgerufen , unabhängig davon, was passiert, im try-Block ( es sei denn, Sie rufen System.exit(int)
oder die Java Virtual Machine schlägt aus einem anderen Grund aus).
Ein logischer Weg, um dies zu denken ist:
- -Code in einem finally-Block platziert ausgeführt werden muss Was geschieht innerhalb des try-Block
- Also, wenn Code im try-Block versucht, einen Wert zurückgeben oder eine Ausnahme der Artikel werfen wird ‚auf dem Regal‘ gesetzt, bis der schließlich Block ausführen kann
- Da Code im finally-Block (per Definition) hat eine hohe Priorität kann es zurückgeben oder werfen, was es will. In diesem Fall etwas links ‚auf dem Regal‘ verworfen.
- Die einzige Ausnahme ist, wenn der VM vollständig Block während des try heruntergefahren z von 'System.exit'
Auch eine Rückkehr in schließlich jede Ausnahme wird wegzuwerfen. http://jamesjava.blogspot.com/2006/03 /dont-return-in-finally-clause.html
schließlich wird immer dann ausgeführt, es sei denn, es gibt Unerwarteter Programmabbruch (wie der Aufruf System.exit (0) ..). so, erhalten Ihre sysout gedruckt
Der finally-Block wird immer dann ausgeführt, es sei denn, es gibt Unerwarteter Programmabbruch, entweder aus einer JVM abstürzen oder von einem Aufruf System.exit(0)
.
Hinzu kommt, dass, kehrte jeder beliebige Wert innerhalb des finally-Block wird den Wert zurück vor der Ausführung der finally-Block, so vorsichtig sein, Überprüfung aller Ausstiegspunkte außer Kraft setzen, wenn versuchen, mit schließlich.
Nein, nicht immer ein Ausnahmefall ist // System.exit (0); bevor der finally-Block ausgeführt schließlich wird verhindert.
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");
}
}
}
Schließlich ist immer laufen, das ist der springende Punkt, nur weil es in dem Code nach der Rückkehr erscheint, bedeutet nicht, dass das ist, wie es umgesetzt werden. Die Java-Laufzeit hat die Aufgabe, diesen Code auszuführen, wenn der try
Block verlassen wird.
Zum Beispiel, wenn Sie die folgenden Schritte aus:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
Die Laufzeit wird in etwa so erzeugen:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
Wenn eine abgefangene Ausnahme der finally
Block geworfen wird, läuft und die Ausnahme ausbreitende fortsetzen wird.
Das ist, weil Sie den Wert von i als 12 zugewiesen, aber den Wert von i auf die Funktion nicht zurück. Der richtige Code lautet wie folgt:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
Da ein finally-Block wird immer dann aufgerufen werden, es sei denn, Sie rufen System.exit()
(oder der Faden stürzt ab).
Antwort ist einfach YES .
INPUT:
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");
}
OUTPUT:
catch
finally
Ja, es wird erhalten genannt. Das ist der springende Punkt ein schließlich Schlüsselwort zu haben. Wenn springen könnte aus dem try / catch-Block nur die überspringen schließlich war blockiert es das gleiche wie das System.out.println außerhalb des try / catch setzen.
Kurz und bündig, in der offiziellen Java Dokumentation (Klicken Sie hier ), es steht geschrieben, dass -
Wenn die JVM beendet, während der Versuch oder Fang Code ausgeführt wird, dann der finally-Block nicht ausgeführt werden kann. Ebenso, wenn der Thread ausführt der Versuch oder Fang Code unterbrochen oder getötet wird, kann der finally-Block weiterhin nicht ausführen, obwohl als Ganzes die Anwendung.
Ja, schließlich wird Block immer ausgeführt werden. Die meisten Entwickler verwenden diesen Block die Schließung der Datenbankverbindung, resultset Objekt, Statement-Objekt und auch in die Java verwendet wintern die Transaktion rückgängig zu machen.
Ja, wird es. Egal, was in Ihrem Versuch oder catch-Block passiert, wenn nichts anderes System.exit () aufgerufen oder JVM abgestürzt. wenn es eine return-Anweisung in dem Block (n) ist, wird schließlich ausgeführt vor dieser return-Anweisung.
Ja, es wird. Nur Fall wird es nicht JVM-Exits oder Abstürze
istSie sich das folgende Programm:
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");
}
}
}
Wie von Java 1.8.162, der obige Code-Block gibt die folgende Ausgabe:
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
Dies bedeutet, dass finally
mit Objekten befreien eine gute Praxis, wie der folgende Code ist:
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.
}
}
Das ist tatsächlich wahr in jeder Sprache ... endlich wird immer vor einer return-Anweisung ausführen, unabhängig davon, wo die Rückkehr in dem Verfahren Körper. Wenn das nicht der Fall war, würde der finally-Block nicht viel Bedeutung haben.
finally
wird ausgeführt, und das ist sicher.
finally
wird nicht ausgeführt in folgenden Fällen:
Fall 1:
Wenn Sie System.exit()
ausgeführt werden.
Fall 2:
Wenn Sie Ihre JVM / Thema stürzt ab.
Fall 3:
Wenn Sie Ihre Ausführung wird zwischen manuell gestoppt in.
Wenn Sie keine Ausnahme behandeln, bevor das Programm beendet wird, führt JVM schließlich blockieren. Es wird nicht nur ausgeführt, wenn die normale Ausführung des Programms bedeutet die Beendigung des Programms aufgrund dieser folgenden Gründen fehlschlagen ..
-
Durch einen fatalen Fehler verursacht, dass der Prozess verursacht abzubrechen.
-
Beendigung des Programms aufgrund Speicher beschädigt.
-
Mit dem Aufruf System.exit ()
-
Wenn das Programm in der Unendlichkeit Schleife geht.
Ja, weil keine Steueranweisung kann verhindern, dass finally
ausgeführt wird.
Hier ist ein Referenzbeispiel, in dem alle Codeblocks ausgeführt werden:
| 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 |
In der Variante unten wird return x;
übersprungen werden. Das Ergebnis wird noch 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--;
}
}
Referenzen, natürlich, verfolgen dessen Status. Dieses Beispiel gibt eine Referenz mit 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
}
}
try
- catch
- finally
sind die Schlüsselwörter für die Ausnahmebehandlung Fall verwenden.
Wie normale explanotory
try {
//code statements
//exception thrown here
//lines not reached if exception thrown
} catch (Exception e) {
//lines reached only when exception is thrown
} finally {
// always executed when the try block is exited
//independent of an exception thrown or not
}
Der finally-Block verhindert Ausführen ...
- Wenn Sie genannt
System.exit(0);
- Wenn JVM beendet wird.
- Fehler in der JVM
Zusätzlich zu @ vibhash Antwort wie keine andere Antwort erklärt, was, wie die in dem Fall ein veränderlichen Objekts geschieht unter .
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 ");
}
}
Will Ausgang
sbupdated
Ich habe versucht, Es ist single threaded.
class Test {
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
Der Haupt-Thread auf Wartezustand für immer sein wird, wird daher schließlich nie, aufgerufen werden
so Konsolenausgabe wird nicht gedruckt string: after wait()
oder finally
Vereinbarte mit @Stephen C ist das obige Beispiel eine der 3. Fall Erwähnung hier :
Hinzufügen mehr solche Endlosschleife Möglichkeiten in folgendem Code:
// import java.util.concurrent.Semaphore;
class Test {
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 e) {
} finally {
System.out.println("finally");
}
}
}
Fall 2: Wenn die JVM stürzt ersten
import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Test {
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: Wie abstürzen Sie eine JVM
Fall 6:. Wenn schließlich Block von Daemon-Thread und alle anderen Nicht-Daemon-Threads Ausgang ausgeführt werden wird, bevor sie schließlich genannt wird
class Test {
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("-------------------------------------------------");
}
}
Ausgang: Dies gilt nicht "endlich" drucken, die "Finally-Block" in "Dämon-Thread" impliziert, wurde nicht ausgeführt
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