Pregunta

Teniendo en cuenta este código, ¿puedo ser? absolutamente seguro que el finally El bloque siempre se ejecuta, pase lo que pase. something() ¿es?

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

Solución

Sí, finally será llamado después de la ejecución del try o catch bloques de código.

las unicas veces finally no serán llamados son:

  1. si invocas System.exit()
  2. Si la JVM falla primero
  3. Si la JVM alcanza un bucle infinito (o alguna otra declaración no interrumpible y sin terminación) en el try o catch bloquear
  4. Si el sistema operativo finaliza por la fuerza el proceso JVM;p.ej., kill -9 <pid> en UNIX
  5. Si el sistema anfitrión muere;por ejemplo, corte de energía, error de hardware, pánico en el sistema operativo, etc.
  6. Si el finally El bloque será ejecutado por un subproceso demonio y todos los demás subprocesos que no son demonios saldrán antes finally se llama

Otros consejos

Código de ejemplo:

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

Producción:

finally trumps return. 
0

Además, aunque es una mala práctica, si hay una declaración de devolución dentro del bloque finalmente, prevalecerá sobre cualquier otra devolución del bloque normal.Es decir, el siguiente bloque devolvería falso:

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

Lo mismo ocurre con el lanzamiento de excepciones desde el bloque finalmente.

Aquí están las palabras oficiales de la Especificación del lenguaje Java.

14.20.2.Ejecución de try-finally y try-catch-finally

A try declaración con un finally El bloque se ejecuta ejecutando primero el try bloquear.Entonces hay una opción:

  • Si la ejecución del try el bloque se completa normalmente, [...]
  • Si la ejecución del try El bloque se completa abruptamente debido a un throw de un valor V, [...]
  • Si la ejecución del try El bloque se completa abruptamente por cualquier otro motivo. R, entonces el finally se ejecuta el bloque.Entonces hay una opción:
    • Si el bloque finalmente se completa normalmente, entonces el try La declaración se completa abruptamente por alguna razón. R.
    • Si el finally El bloque se completa abruptamente por algún motivo. S, entonces el try La declaración se completa abruptamente por alguna razón. S (y razon R esta descartado).

La especificación para return en realidad hace esto explícito:

JLS 14.17 La Declaración de Retorno

ReturnStatement:
     return Expression(opt) ;

A return declaración sin Expression intentos para transferir el control al invocador del método o constructor que lo contiene.

A return declaración con un Expression intentos transferir el control al invocador del método que lo contiene;el valor de la Expression se convierte en el valor de la invocación del método.

Las descripciones anteriores dicen "intentos transferir el control"en lugar de simplemente"control de transferencias"porque si hay alguno try declaraciones dentro del método o constructor cuyo try Los bloques contienen el return declaración, entonces cualquier finally cláusulas de esos try Las declaraciones se ejecutarán, en orden, desde la más interna a la más externa, antes de que el control se transfiera al invocador del método o constructor.Finalización abrupta de un finally cláusula puede interrumpir la transferencia de control iniciada por un return declaración.

Además de las otras respuestas, es importante señalar que 'finalmente' tiene derecho a anular cualquier excepción/valor devuelto por el bloque try..catch.Por ejemplo, el siguiente código devuelve 12:

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

De manera similar, el siguiente método no genera una excepción:

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

Mientras que el siguiente método lo arroja:

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

Probé el ejemplo anterior con una ligera modificación.

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

El código anterior genera:

finalmente triunfa sobre el regreso.
2

Esto se debe a que cuando return i; es ejecutado i tiene un valor 2.Después de esto el finally Se ejecuta el bloque donde se asigna 12 a i y luego System.out se ejecuta out.

Después de ejecutar el finally bloquear el try El bloque devuelve 2, en lugar de devolver 12, porque esta declaración de devolución no se ejecuta nuevamente.

Si depura este código en Eclipse, tendrá la sensación de que después de ejecutar System.out de finally bloquear el return declaracion de try El bloque se ejecuta nuevamente.Pero este no es el caso.Simplemente devuelve el valor 2.

He aquí una elaboración de la respuesta de kevin.Es importante saber que la expresión a devolver se evalúa antes finally, incluso si se devuelve después.

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

Producción:

X
finally trumps return... sort of
0

Esa es la idea de un bloque final.Le permite asegurarse de realizar limpiezas que de otro modo podrían omitirse cuando regrese, entre otras cosas, por supuesto.

Finalmente lo llaman independientemente de lo que pase en el bloque de prueba (a menos que llama System.exit(int) o la máquina virtual Java se desconecta por algún otro motivo).

Una forma lógica de pensar en esto es:

  1. El código colocado en un bloque finalmente debe ejecutarse pase lo que pase dentro del bloque de prueba
  2. Entonces, si el código en el bloque try intenta devolver un valor o generar una excepción, el elemento se coloca "en el estante" hasta que el bloque finalmente pueda ejecutarse.
  3. Debido a que el código en el bloque finalmente tiene (por definición) una alta prioridad, puede devolver o lanzar lo que quiera.En cuyo caso, todo lo que quede "en el estante" se descarta.
  4. La única excepción a esto es si la VM se apaga por completo durante el bloque de prueba, por ejemplo.por 'Sistema.salida'

Además, un retorno finalmente descartará cualquier excepción. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

finalmente siempre se ejecuta a menos que haya una terminación anormal del programa (como llamar a System.exit(0)...).Entonces, tu salida del sistema se imprimirá.

El bloque finalmente siempre se ejecuta a menos que haya una terminación anormal del programa, ya sea como resultado de una falla de JVM o de una llamada a System.exit(0).

Además de eso, cualquier valor devuelto dentro del bloque finalmente anulará el valor devuelto antes de la ejecución del bloque finalmente, así que tenga cuidado de verificar todos los puntos de salida cuando utilice try finalmente.

No, no siempre un caso de excepción es // System.exit (0);antes de que el bloque finalmente impida que finalmente se ejecute.

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

Finalmente siempre se ejecuta, ese es el punto, el hecho de que aparezca en el código después del retorno no significa que así sea como se implemente.El tiempo de ejecución de Java tiene la responsabilidad de ejecutar este código al salir del try bloquear.

Por ejemplo, si tiene lo siguiente:

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

El tiempo de ejecución generará algo como esto:

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

Si se lanza una excepción no detectada, finally El bloque se ejecutará y la excepción continuará propagándose.

Esto se debe a que asignaste el valor de i como 12, pero no devolviste el valor de i a la función.El código correcto es el siguiente:

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

Porque siempre se llamará a un bloque finalmente a menos que usted llame System.exit() (o el hilo falla).

la respuesta es simple .

APORTE:

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

PRODUCCIÓN:

catch
finally

Sí, lo llamarán.Ese es el objetivo de tener una palabra clave finalmente.Si saltar del bloque try/catch pudiera simplemente omitir el bloque finalmente, era lo mismo que poner System.out.println fuera del try/catch.

De manera concisa, en la documentación oficial de Java (haga clic en aquí), está escrito que -

Si el JVM sale mientras se ejecuta el código de prueba o captura, entonces el bloque finalmente no puede ejecutarse.Del mismo modo, si el hilo que ejecuta el código de prueba o de captura se interrumpe o mata, el bloque finalmente puede no ejecutarse a pesar de que la aplicación en su conjunto continúa.

Sí, el bloqueo final siempre se ejecuta.La mayoría de los desarrolladores utilizan este bloque para cerrar la conexión de la base de datos, el objeto del conjunto de resultados, el objeto de declaración y también lo utilizan en la hibernación de Java para revertir la transacción.

Sí, lo será.No importa lo que suceda en su bloque try o catch a menos que se llame a System.exit() o la JVM falle.si hay alguna declaración de devolución en los bloques, finalmente se ejecutará antes de esa declaración de devolución.

Sí lo será.El único caso en el que no será así es que la JVM se cierre o se bloquee.

Considere el siguiente programa:

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

A partir de Java 1.8.162, el bloque de código anterior proporciona el siguiente resultado:

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

esto significa que usando finally liberar objetos es una buena práctica como el siguiente código:

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

En realidad, eso es cierto en cualquier idioma... finalmente siempre se ejecutará antes de una declaración de retorno, sin importar dónde se encuentre ese retorno en el cuerpo del método.Si ese no fuera el caso, el bloque finalmente no tendría mucho significado.

finally se ejecutará y eso es seguro.

finally no se ejecutará en los siguientes casos:

caso 1 :

cuando estas ejecutando System.exit().

caso 2:

Cuando su JVM/Thread falla.

caso 3:

Cuando su ejecución se detiene manualmente.

Si no maneja la excepción, antes de finalizar el programa, JVM ejecuta el bloque finalmente.No se ejecutará solo si la ejecución normal del programa falla, lo que significa la terminación del programa debido a las siguientes razones.

  1. Provocando un error fatal que hace que el proceso se aborte.

  2. Terminación del programa debido a memoria corrupta.

  3. Llamando a System.exit()

  4. Si el programa entra en un bucle infinito.

Sí porque sin declaración de control puede prevenir finally de ser ejecutado.

Aquí hay un ejemplo de referencia, donde se ejecutarán todos los bloques de código:

| 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      |

En la variante siguiente, return x; será omitido.El resultado sigue siendo 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--;
    }
}

Las referencias, por supuesto, rastrean su estado.Este ejemplo devuelve una referencia con 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 son las palabras clave para utilizar casos de manejo de excepciones.
Como explicativo normal.

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
}

El bloque finalmente impide la ejecución...

  • Cuando llamaste System.exit(0);
  • Si JVM sale.
  • Errores en la JVM

Añadiendo a La respuesta de @vibhash ya que ninguna otra respuesta explica lo que sucede en el caso de un objeto mutable como el siguiente.

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

Salida

sbupdated 

Intenté esto, está en un solo rostro.

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

El hilo principal estará en estado de espera para siempre, por lo tanto, finalmente nunca será llamado.

entonces la salida de la consola no imprimirá la cadena: after wait() o finally

De acuerdo con @Stephen C, el ejemplo anterior es uno de los terceros casos mencionados. aquí:

Agregando más posibilidades de bucle infinito en el siguiente código:

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

Caso 2:Si la JVM falla primero

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

Árbitro: ¿Cómo se bloquea una JVM?

Caso 6:Si finalmente el bloque va a ser ejecutado por un subproceso demonio y todos los demás subprocesos que no son demonios salen antes de que finalmente se llame.

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

producción:Esto no imprime "finalmente", lo que implica que "Finalmente bloquear" en el "hilo del demonio" no se ejecutó.

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top