lanza Excepción en finalmente bloques


¿Hay una manera elegante de manejar las excepciones que se lanzan en el bloque finally?

Por ejemplo:

try {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
finally {
   try{
     resource.close();
   }
   catch( Exception ex ) {
     // Could not close the resource?
   }
}

¿Cómo evitar la try/catch ¿en el bloque finally?

Author: bluish, 2009-01-27

14 answers

Normalmente lo hago así:

try {
  // Use the resource.
} catch( Exception ex ) {
  // Problem with the resource.
} finally {
  // Put away the resource.
  closeQuietly( resource );
}

En otro lugar:

protected void closeQuietly( Resource resource ) {
  try {
    if (resource != null) {
      resource.close();
    }
  } catch( Exception ex ) {
    log( "Exception during Resource.close()", ex );
  }
}
 72
Author: Darron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-15 18:09:47

Normalmente uso uno de los métodos closeQuietly en org.apache.commons.io.IOUtils:

public static void closeQuietly(OutputStream output) {
    try {
        if (output != null) {
            output.close();
        }
    } catch (IOException ioe) {
        // ignore
    }
}
 25
Author: CJS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-22 09:55:31

Si estás usando Java 7, y resource implementa AutoClosable, puedes hacer esto (usando InputStream como ejemplo):

try (InputStream resource = getInputStream()) {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
 21
Author: Kevin Wong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-09 06:55:52

Podría decirse que es un poco exagerado, pero tal vez útil si estás dejando que las excepciones se formen burbujas y no puedes registrar nada desde tu método (por ejemplo, porque es una biblioteca y prefieres que el código de llamada maneje las excepciones y el registro):

Resource resource = null;
boolean isSuccess = false;
try {
    resource = Resource.create();
    resource.use();
    // Following line will only run if nothing above threw an exception.
    isSuccess = true;
} finally {
    if (resource != null) {
        if (isSuccess) {
            // let close throw the exception so it isn't swallowed.
            resource.close();
        } else {
            try {
                resource.close();
            } catch (ResourceException ignore) {
                // Just swallow this one because you don't want it 
                // to replace the one that came first (thrown above).
            }
        }
    }
}

ACTUALIZACIÓN: Investigué un poco más y encontré una gran entrada de blog de alguien que claramente ha pensado en esto más que yo: http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html He va un paso más allá y combina las dos excepciones en una sola, que podría ser útil en algunos casos.

 8
Author: MB.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-14 11:45:42

A partir de Java 7 ya no necesita cerrar explícitamente los recursos en un bloque finally en su lugar puede usar la sintaxis try-with-resources. La instrucción try-with-resources es una instrucción try que declara uno o más recursos. Un recurso es un objeto que debe cerrarse después de que el programa haya terminado con él. La instrucción try-with-resources garantiza que cada recurso se cierre al final de la instrucción. Cualquier objeto que implemente java.lang.AutoCloseable, que incluye todos los objetos que implementan java. io. Closeable, se pueden utilizar como recurso.

Supongamos el siguiente código:

try( Connection con = null;
     Statement stmt = con.createStatement();
     Result rs= stmt.executeQuery(QUERY);)
{  
     count = rs.getInt(1);
}

Si ocurre alguna excepción, el método close será llamado a cada uno de estos tres recursos en orden opuesto en el que fueron creados. Significa que el método close se llamaría primero para ResultSetm, luego para la Instrucción y al final para el objeto de conexión.

También es importante saber que cualquier excepción que ocurra cuando los métodos de cierre es se suprimen las llamadas automáticas. Estas excepciones suprimidas se pueden recuperar mediante el método getsuppressed () definido en la clase Throwable .

Fuente: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

 5
Author: Soroosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-09 17:26:03

Ignorar las excepciones que ocurren en un bloque 'finally' es generalmente una mala idea a menos que uno sepa cuáles serán esas excepciones y qué condiciones representarán. En el patrón de uso normal try/finally, el bloque try coloca las cosas en un estado que el código externo no esperará, y el bloque finally restaura el estado de esas cosas a lo que el código externo espera. Fuera del código que captura una excepción generalmente esperará que, a pesar de la excepción, todo ha sido restaurado a un estado normal. Por ejemplo, supongamos que algún código inicia una transacción y luego intenta agregar dos registros; el bloque" finally "realiza una operación de" reversión si no se confirma". Un llamador puede estar preparado para que ocurra una excepción durante la ejecución de la segunda operación" add", y puede esperar que si detecta tal excepción, la base de datos estará en el estado que estaba antes de que se intentara cualquiera de las operaciones. Sin embargo, si se produce una segunda excepción durante la reversión, las cosas malas podría suceder si la persona que llama hace suposiciones sobre el estado de la base de datos. La falla de reversión representa una crisis mayor one una que no debería ser atrapada por el código esperando una mera excepción de "No agregar registro".

Mi inclinación personal sería tener un método finalmente captura excepciones que se producen y envolverlas en una "CleanupFailedException", reconociendo que tal falla representa un problema importante y tal excepción no debe ser tomada a la ligera.

 3
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-09 20:45:01

Una solución, si las dos Excepciones son dos clases diferentes

try {
    ...
    }
catch(package1.Exception err)
   {
    ...
   }
catch(package2.Exception err)
   {
   ...
   }
finally
  {
  }

Pero a veces no se puede evitar este segundo intento-captura. por ejemplo, para cerrar una corriente

InputStream in=null;
try
 {
 in= new FileInputStream("File.txt");
 (..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
 }
catch(SQLException err)
 {
 //handle exception
 }
finally
 {
 //at the end, we close the file
 if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
 }
 2
Author: Pierre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 21:35:11

¿por Qué quieres evitar el bloqueo adicional? Dado que el bloque finally contiene operaciones "normales" que pueden lanzar una excepción Y desea que el bloque finally se ejecute completamente, debe capturar excepciones.

Si no espera que el bloque finally lance una excepción y no sabe cómo manejar la excepción de todos modos (simplemente volcaría stack trace), deje que la excepción suba la pila de llamadas (elimine el try-catch del bloque finally).

Si desea reducir al escribir, podría implementar un bloque externo "global" try-catch, que capturará todas las excepciones lanzadas en finalmente bloques:

try {
    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }
} catch (Exception ex) {
    ...
}
 1
Author: Eduard Wirch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 21:42:03

Después de mucha consideración, encuentro el siguiente código mejor:

MyResource resource = null;
try {
    resource = new MyResource();
    resource.doSomethingFancy();
    resource.close(); 
    resource = null;  
} finally {
    closeQuietly(resource)
}

void closeQuietly(MyResource a) {
    if (a!=null)
        try {
             a.close();
        } catch (Exception e) {
             //ignore
        }
}

Ese código garantiza lo siguiente:

  1. El recurso se libera cuando el código terminado
  2. Las excepciones lanzadas al cerrar el recurso no se consumen sin procesarlas.
  3. El código no intenta cerrar el recurso dos veces, no se creará ninguna excepción innecesaria.
 1
Author: Grogi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-17 13:36:50

Si puede, debe probar para evitar la condición de error para empezar.

try{...}
catch(NullArgumentException nae){...}
finally
{
  //or if resource had some useful function that tells you its open use that
  if (resource != null) 
  {
      resource.Close();
      resource = null;//just to be explicit about it was closed
  }
}

También probablemente solo debería capturar excepciones de las que pueda recuperarse, si no puede recuperarse, deje que se propague al nivel superior de su programa. Si no puede probar una condición de error, tendrá que rodear su código con un bloque try catch como ya lo ha hecho (aunque recomendaría aún detectar errores específicos y esperados).

 0
Author: Ken Henderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 21:39:29

Podría refactorizar esto en otro método ...

public void RealDoSuff()
{
   try
   { DoStuff(); }
   catch
   { // resource.close failed or something really weird is going on 
     // like an OutOfMemoryException 
   }
}

private void DoStuff() 
{
  try 
  {}
  catch
  {
  }
  finally 
  {
    if (resource != null) 
    {
      resource.close(); 
    }
  }
}
 0
Author: Sam Saffron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 21:50:30

, normalmente hago esto:

MyResource r = null;
try { 
   // use resource
} finally {   
    if( r != null ) try { 
        r.close(); 
    } catch( ThatSpecificExceptionOnClose teoc ){}
}

Justificación: Si he terminado con el recurso y el único problema que tengo es cerrarlo, no hay mucho que pueda hacer al respecto. Tampoco tiene sentido matar todo el hilo si he terminado con el recurso de todos modos.

Este es uno de los casos en los que, al menos para mí, es seguro ignorar esa excepción marcada.

Hasta el día de hoy no he tenido ningún problema con este modismo.

 0
Author: OscarRyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 22:40:58
try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

Trabajo hecho. No hay pruebas nulas. Captura única, incluye excepciones de adquisición y liberación. Por supuesto, puede usar el modismo Execute Around y solo tiene que escribirlo una vez para cada tipo de recurso.

 0
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-27 13:50:57

Cambiando Resource de mejor respuesta a Closeable

Streams implementa Closeable Por lo tanto, puede reutilizar el método para todos los streams

protected void closeQuietly(Closeable resource) {
    if (resource == null) 
        return;
    try {
        resource.close();
    } catch (IOException e) {
        //log the exception
    }
}
 0
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-15 09:11:32