¿Está bien tener una instrucción catch vacía?

53

Lo pensé y no pude dar un ejemplo. ¿Por qué alguien querría atrapar una excepción y no hacer nada al respecto? ¿Puede dar un ejemplo? Tal vez solo sea algo que nunca se debe hacer.

    
pregunta ysolik 04.11.2010 - 15:08

15 respuestas

74

Lo hago todo el tiempo con cosas como errores de conversión en D:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

Dicho esto, creo que todos los bloques de captura deberían tener algo , incluso si ese algo es solo un comentario que explica por qué usted ignora la excepción.

Editar: También quiero enfatizar que, si vas a hacer algo como esto, debes tener cuidado de solo detectar la excepción específica que quieres ignorar. Hacer un antiguo catch {} es casi siempre algo malo.

    
respondido por el dsimcha 04.11.2010 - 16:24
49

Un ejemplo en el que creo que está bien simplemente tragar la excepción sin hacer nada, incluso registrar la excepción, es el propio código de registro.

Si intentaste registrar algo y obtuviste una excepción, no hay mucho que puedas hacer al respecto:

  • no puedes registrarlo, por supuesto;
  • es posible que pueda recurrir a un mecanismo de registro de reserva, pero la mayoría de las aplicaciones no son tan sofisticadas, y para aquellas que son lo suficientemente sofisticadas, surgirá el mismo problema de diseño con el mecanismo de registro de reserva;
  • falla rápida: será una solución demasiado radical para la mayoría de las aplicaciones;
  • lanzar una excepción no servirá de mucho, ya que terminará en una declaración catch en la pila que casi seguro intentará registrarla ...

Eso te deja con la opción "menos malvada" de tragarlo silenciosamente, permitiendo que la aplicación siga realizando su trabajo principal, pero comprometiendo la capacidad de solucionarlo.

    
respondido por el kdubinets 04.11.2010 - 20:03
8

Si se produce una excepción mediante una operación que de todos modos era opcional, es posible que no haya nada que hacer. Puede que no sea útil para iniciar sesión. En ese caso, es posible que solo quieras atraparlo y no hacer nada.

Si estás haciendo esto, incluye un comentario. Siempre comente cualquier cosa que parezca un error (fallido en una declaración switch , bloque vacío catch , asignación en una condición).

Podría argumentar que esto no es un uso adecuado de las excepciones, pero eso es para otra pregunta.

    
respondido por el David Thornley 04.11.2010 - 16:16
6

Los bloques catch vacíos son un olor de código en la mayoría de los idiomas. La idea principal es usar excepciones para situaciones excepcionales y no usarlas para el control lógico. Todas las excepciones deben manejarse en algún lugar.

Como consecuencia de este enfoque, cuando programa una capa de aplicación en particular, tiene varias opciones:

  • no hacer nada acerca de la excepción. Será capturado y manejado por una capa diferente
  • cógela y realiza la acción correctiva.
  • atrapa, haz algo, pero vuelve a lanzarlo para que otra capa lo maneje

Esto realmente no deja espacio para hacer nada, vaciar catch blocks.

EDITADO PARA AGREGAR : suponga que está programando en un lenguaje en el que lanzar excepciones es la forma normal de controlar la lógica del programa (una de las alternativas a goto ). Entonces, un bloque catch vacío en un programa escrito en este idioma es muy parecido a un bloque else vacío en un idioma tradicional (o no hay un bloque else ). Sin embargo, creo que este no es el estilo de programación recomendado por las comunidades de desarrollo C #, Java o C ++.

    
respondido por el azheglov 04.11.2010 - 16:52
6

En algunos casos, Java requiere que manejes una excepción que, bajo ninguna circunstancia, puede suceder. Considere este código:

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}
  

Cada implementación de Java   Se requiere plataforma para soportar el   siguientes conjuntos de caracteres estándar.

     

...

     

UTF-8

Sin romper su plataforma Java, simplemente no hay forma de causar esta excepción. Entonces, ¿por qué molestarse en manejarlo? Pero no puedes simplemente omitir la cláusula try-catch.

    
respondido por el user281377 04.11.2010 - 22:12
5

Como regla general, no. O bien desea lanzar la excepción en la pila o registrar lo que sucedió.

Sin embargo, a menudo hago esto cuando analizo cadenas y las convierto a números (especialmente en proyectos de mapeo que son de la variedad de uso y desecho).

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;
    
respondido por el Fil 04.11.2010 - 15:41
2

En mi humilde experiencia, rara vez es algo bueno. Su kilometraje puede variar sin embargo.

Casi cada vez que he visto esto en nuestra base de códigos, se debe a que he rastreado un error que la excepción comido ha ocultado. Para decirlo de otra manera, al no proporcionar ningún código, la aplicación no tiene forma de indicar un error ni de realizar otra acción.

A veces, en las capas API, por ejemplo, es posible que no desee o no pueda dejar pasar las excepciones, por lo que, en ese caso, tiendo a intentar capturar lo más genérico y luego registrarlas. Una vez más, al menos para dar una oportunidad a una sesión de depuración / diagnóstico.

Normalmente, si debe estar vacío, lo menos que hago es poner una afirmación de algún tipo, por lo que al menos algo sucede durante una sesión de depuración. Dicho esto, si no puedo manejarlo, tiendo a omitirlos por completo.

    
respondido por el DevSolo 04.11.2010 - 15:42
2

OMI, hay un lugar donde las declaraciones de captura vacías están bien. En los casos de prueba en los que se espera una excepción:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}
    
respondido por el Victor Hurdugaci 04.11.2010 - 19:04
2

Creo que hay ciertos casos en los que está justificado tener una cláusula catch vacía: estos son casos en los que desea que el código continúe si falla una operación en particular. Sin embargo, creo que este patrón puede ser fácilmente usado en exceso, por lo que cada uso debe examinarse de cerca para asegurarse de que no haya una mejor manera de manejarlo. En particular, esto nunca debe hacerse si deja el programa en un estado incoherente o si podría hacer que otra parte del código falle más adelante.

    
respondido por el o. nate 04.11.2010 - 19:43
2

En algunos casos, la excepción no es del todo excepcional; de hecho, se espera. Considera este ejemplo:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

Ya que no hay un método isAlive () en java.lang.Process (), casi la única forma de verificar si aún está vivo es llamar a exitValue (), que lanza una excepción IllegalThreadStateException si el proceso aún está en ejecución.

    
respondido por el user281377 10.11.2010 - 10:43
1

No creo en no tener algún nivel de alerta cuando se produce una excepción. ¿No debería ser uno de los objetivos de la programación mejorar el código? Si se produce una excepción el 10% del tiempo y nunca se sabe, la excepción siempre será tan mala o peor.

Sin embargo, sí veo el otro lado, que si la excepción no causa un daño real en el procesamiento del código, entonces ¿por qué exponer al usuario? La solución que implemento normalmente es tenerla registrada por mi clase de registrador (es decir, en cada clase que escribo en el trabajo).

Si es una excepción benigna, hago una llamada al método .Debug () de mi registrador; de lo contrario, Logger.Error () (y (quizás) lanzar).

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

Por cierto, en mi implementación de mi registrador, hacer una llamada al método .Debug () solo lo registrará si mi archivo App.Config especifica que el nivel de registro de ejecución del programa está en modo de depuración.

    
respondido por el Tim Claason 04.11.2010 - 17:14
0

La única vez que realmente tuve que hacer algo como esto fue con una clase de registro para una aplicación de consola. Hubo un controlador de captura global de nivel superior que emitió el error a STDOUT, registró el error en un archivo y luego cerró la aplicación con un código de error > 0.

El problema aquí era que a veces, el registro en el archivo fallaba. Los permisos de directorio le impidieron escribir el archivo, el archivo se bloqueó exclusivamente, lo que sea. Si eso sucediera, no podría manejar la excepción de la misma manera que lo había hecho en otro lugar (captura, registrar los detalles relevantes , ajustar un mejor tipo de excepción, etc.) porque el registro de los detalles de la excepción causó el registrador para pasar por las mismas acciones (intentando escribir en un archivo) que ya habían fallado. Cuando volvieron a fallar ... ves a dónde voy. Se mete en un bucle infinito.

Si elimina algunos de los bloques try {}, puede terminar con la excepción que aparece en un cuadro de mensaje (no lo que desea para una aplicación de configuración silenciosa). Así que en ese método que escribe en el archivo de registro, tengo un controlador de captura vacío. Esto no entierra el error, ya que todavía obtiene el código de error > 0, simplemente detiene el bucle infinito y permite que la aplicación salga correctamente.

Hay un comentario, por supuesto, que explica por qué está vacío.

(Iba a publicar esto antes, solo temía que me echaran al olvido. Como no soy el único, sin embargo ...)

    
respondido por el JohnL 04.11.2010 - 16:20
0

Está bien en una situación en la que se debe ejecutar una secuencia, sin importar qué se coloque al final la parte más crítica.

Por ejemplo. En la comunicación de control de movimiento del host al controlador. En situaciones de emergencia, hay una serie de pasos de preparación para abortar el movimiento, detener la generación de la trayectoria, desacelerar los motores, habilitar las pausas, deshabilitar el amplificador y, después, debe eliminar la alimentación del bus. Todo debe suceder de forma secuencial y si uno de los pasos falla, el resto de los pasos debe ejecutarse de todos modos, incluso con el riesgo aceptado de dañar el hardware. Digamos que incluso si todo lo anterior falla, la alimentación del bus de eliminación debe ocurrir de todos modos.

    
respondido por el user7071 05.11.2010 - 01:09
0

Cerrar los recursos del sistema con gracia para recuperarse de un error

Por ejemplo. Si está ejecutando un servicio en segundo plano que no proporciona comentarios al usuario, es posible que no desee enviar una indicación del error al usuario, pero sí debe cerrar los recursos. siendo usado de una manera elegante.

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

Lo ideal sería utilizar la captura en el modo de depuración para detectar errores e imprimirlos en la consola o en un archivo de registro para la prueba. En un entorno de producción, generalmente se espera que los servicios en segundo plano no interrumpan al usuario cuando se produce un error, por lo que debe suprimirse la salida de error.

    
respondido por el Evan Plaice 20.11.2010 - 02:43
0

La verificación de existencia es un buen caso de uso:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

Otro caso es cuando se usa una cláusula finally :

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

Hay una propuesta para permitir la omisión del enlace de captura en ECMAScript que pertenece a esto y casos de uso similares.

Referencias

respondido por el Paul Sweatte 19.09.2018 - 15:44

Lea otras preguntas en las etiquetas

Comentarios Recientes

Claro, digamos que hay una declaración de voluntad en el controlador de eventos, pero queremos tomar automáticamente quién será la persona responsable de colocar nuestra salida de registro al final de nuestro archivo de registro, en lugar de escribir nuestro propio archivo de registro. Entonces, si no hay un "Por favor, déjame volver a mí" al final, podemos detenernos allí e ignorar todas las afirmaciones de excepción vacías. No necesariamente necesitamos restablecer la pila, o usar una llamada no operativa... Lee mas