without try practices practice new handling exceptions example custom catch best all design exception-handling try-catch

design - try - ¿Por qué los bloques de captura vacíos son una mala idea?



try catch java (20)

Acabo de ver una pregunta sobre try-catch , ¿qué personas (incluido Jon Skeet) dicen que los bloques de captura vacíos son una mala idea? ¿Por qué esto? ¿No hay una situación donde una captura vacía no es una decisión de diseño incorrecta?

Quiero decir, por ejemplo, a veces quieres obtener información adicional de algún lugar (servicio web, base de datos) y realmente no te importa si obtienes esta información o no. Entonces, si intentas conseguirlo, y si pasa algo, está bien, solo añadiré un "catch (Exception ignored) {}" y eso es todo


Quiero decir, por ejemplo, a veces quieres obtener información adicional de algún lugar (servicio web, base de datos) y realmente no te importa si obtienes esta información o no. Entonces, si intentas conseguirlo, y si pasa algo, está bien, solo añadiré un "catch (Exception ignored) {}" y eso es todo

Entonces, yendo con su ejemplo, es una mala idea en ese caso porque está atrapando e ignorando todas las excepciones. Si capturara solo EInfoFromIrrelevantSourceNotAvailable e EInfoFromIrrelevantSourceNotAvailable , estaría bien, pero no es así. También está ignorando ENetworkIsDown , que puede o no ser importante. Está ignorando ENetworkCardHasMelted y EFPUHasDecidedThatOnePlusOneIsSeventeen , que sin duda son importantes.

Un bloqueo de catch vacío no es un problema si está configurado para capturar (e ignorar) excepciones de ciertos tipos que usted sabe que no son importantes. Las situaciones en las que es una buena idea suprimir e ignorar silenciosamente todas las excepciones, sin detenerse a examinarlas primero para ver si son esperadas / normales / irrelevantes o no, son extremadamente raras.


Creo que está bien si detecta un tipo de excepción particular del cual sabe que solo se planteará por un motivo en particular , y espera esa excepción y realmente no necesita hacer nada al respecto.

Pero incluso en ese caso, un mensaje de depuración podría estar en orden.


Creo que un bloque catch completamente vacío es una mala idea porque no hay forma de inferir que ignorar la excepción fue el comportamiento previsto del código. No es necesariamente malo tragar una excepción y devolver un valor falso o nulo o algún otro valor en algunos casos. El framework .net tiene muchos métodos de "prueba" que se comportan de esta manera. Como regla general, si traga una excepción, agregue un comentario y una declaración de registro si la aplicación admite el registro.


En general, solo debe detectar las excepciones que realmente puede manejar. Eso significa ser tan específico como sea posible cuando capture excepciones. Capturar todas las excepciones rara vez es una buena idea e ignorar todas las excepciones es casi siempre una muy mala idea.

Solo puedo pensar en algunos casos en los que un bloque de captura vacío tiene algún propósito significativo. Si cualquier excepción específica, la captura se "maneja" simplemente reintentando la acción, no habría necesidad de hacer nada en el bloque catch. Sin embargo, sería una buena idea registrar el hecho de que se produjo la excepción.

Otro ejemplo: CLR 2.0 cambió la forma en que se tratan las excepciones no controladas en el hilo del finalizador. Antes de 2.0, se permitió que el proceso sobreviviera a este escenario. En el CLR actual, el proceso finaliza en caso de una excepción no controlada en el hilo del finalizador.

Tenga en cuenta que solo debe implementar un finalizador si realmente necesita uno e incluso entonces debe hacer un poco como sea posible en el finalizador. Pero si cualquier trabajo que tu finalizador deba hacer podría arrojar una excepción, debes elegir entre el menor de dos males. ¿Desea cerrar la aplicación debido a la excepción no controlada? ¿O quieres proceder en un estado más o menos indefinido? Al menos en teoría, este último puede ser el menor de los dos males en algunos casos. En esos casos, el bloque catch vacío evitaría que el proceso finalice.


Encuentro que lo más molesto con declaraciones de catch vacías es cuando lo hizo algún otro programador. Lo que quiero decir es que cuando necesitas depurar el código de otra persona, cualquier declaración de captura vacía hace que tal empresa sea más difícil de lo que necesita. Las declaraciones de capturas en mi humilde opinión siempre deben mostrar algún tipo de mensaje de error: incluso si el error no se maneja, al menos debería detectarlo (alt. Solo en el modo de depuración)


Esto va de la mano con "No usar excepciones para controlar el flujo del programa" y "Usar excepciones solo para circunstancias excepcionales". Si esto se hace, las excepciones solo deberían ocurrir cuando hay un problema. Y si hay un problema, no quieres fallar silenciosamente. En las anomalías raras donde no es necesario manejar el problema, al menos debe registrar la excepción, en caso de que la anomalía ya no sea una anomalía. Lo único peor que fallar es fallar silenciosamente.


Hay raros casos en que puede justificarse. En Python, a menudo se ve este tipo de construcción:

try: result = foo() except ValueError: result = None

Por lo tanto, podría estar bien (dependiendo de su aplicación) hacer:

result = bar() if result == None: try: result = foo() except ValueError: pass # Python pass is equivalent to { } in curly-brace languages # Now result == None if bar() returned None *and* foo() failed

En un proyecto .NET reciente, tuve que escribir código para enumerar archivos DLL de complemento para encontrar clases que implementan una determinada interfaz. El fragmento de código relevante (en VB.NET, lo siento) es:

For Each dllFile As String In dllFiles Try '' Try to load the DLL as a .NET Assembly Dim dll As Assembly = Assembly.LoadFile(dllFile) '' Loop through the classes in the DLL For Each cls As Type In dll.GetExportedTypes() '' Does this class implement the interface? If interfaceType.IsAssignableFrom(cls) Then '' ... more code here ... End If Next Catch ex As Exception '' Unable to load the Assembly or enumerate types -- just ignore End Try Next

Aunque incluso en este caso, admito que registrar la falla en alguna parte probablemente sea una mejora.


Hay situaciones en las que puede usarlas, pero deben ser muy poco frecuentes. Las situaciones en las que podría usar uno incluyen:

  • registro de excepción; dependiendo del contexto, es posible que desee una excepción no controlada o un mensaje publicado en su lugar.

  • situaciones técnicas repetitivas, como renderizado o procesamiento de sonido o una devolución de llamada de la caja de lista, donde el comportamiento mismo demostrará el problema, lanzar una excepción simplemente se interpondrá en el camino, y registrar la excepción probablemente solo resulte en 1000 de mensajes "fallidos a XXX" .

  • programas que no pueden fallar, aunque todavía deberían, al menos, estar registrando algo.

para la mayoría de las aplicaciones de winforms, he descubierto que basta con tener una declaración de prueba única para cada entrada de usuario. Utilizo los siguientes métodos: (AlertBox es solo un contenedor de MessageBox.Show rápido)

public static bool TryAction(Action pAction) { try { pAction(); return true; } catch (Exception exception) { LogException(exception); return false; } } public static bool TryActionQuietly(Action pAction) { try { pAction(); return true; } catch(Exception exception) { LogExceptionQuietly(exception); return false; } } public static void LogException(Exception pException) { try { AlertBox(pException, true); LogExceptionQuietly(pException); } catch { } } public static void LogExceptionQuietly(Exception pException) { try { Debug.WriteLine("Exception: {0}", pException.Message); } catch { } }

Entonces, cada controlador de eventos puede hacer algo como:

private void mCloseToolStripMenuItem_Click(object pSender, EventArgs pEventArgs) { EditorDefines.TryAction(Dispose); }

o

private void MainForm_Paint(object pSender, PaintEventArgs pEventArgs) { EditorDefines.TryActionQuietly(() => Render(pEventArgs)); }

Teóricamente, podría tener TryActionSilently, que podría ser mejor para realizar llamadas de modo que una excepción no genere una cantidad infinita de mensajes.


Las excepciones solo se deben lanzar si realmente hay una excepción, algo que sucede más allá de la norma. Un bloque de catch vacío básicamente dice "algo malo está pasando, pero simplemente no me importa". Esta es una mala idea.

Si no desea manejar la excepción, permita que se propague hacia arriba hasta que llegue a algún código que pueda manejarla. Si nada puede manejar la excepción, debería quitar la aplicación.


Los bloques de captura vacíos generalmente se ponen porque el codificador no sabe realmente lo que están haciendo. En mi organización, un bloque de catch vacío debe incluir un comentario sobre por qué no hacer nada con la excepción es una buena idea.

En una nota relacionada, la mayoría de la gente no sabe que un bloque try {} se puede seguir con un catch {} o un finally {}, solo se requiere uno.


Los bloques de captura vacíos son una indicación de que un programador no sabe qué hacer con una excepción. Están suprimiendo la excepción de que posiblemente burbujee y sea manejado correctamente por otro bloque try. Siempre intenta hacer algo con la excepción que estás atrapando.


No me extendería tanto como para decir que quien usa bloques de captura vacíos es un mal programador y no sabe lo que está haciendo ...

Yo uso bloques de captura vacíos si es necesario. A veces, el programador de la biblioteca que estoy consumiendo no sabe lo que hace y arroja excepciones incluso en situaciones en que nadie lo necesita.

Por ejemplo, considere alguna biblioteca de servidores http, no me importaría menos si el servidor arroja una excepción porque el cliente se ha desconectado y no se pudo enviar index.html .


Nunca deberías tener un bloque de catch vacío. Es como esconder un error que conoces. Por lo menos, debe escribir una excepción en un archivo de registro para revisarlo más tarde si está presionado por el tiempo.


Per Josh Bloch - Elemento 65: No ignore las excepciones de Java efectivo :

  1. Un bloque catch vacío derrota el propósito de excepciones
  2. Por lo menos, el bloque catch debe contener un comentario que explique por qué es apropiado ignorar la excepción.

Por lo general, el try-catch vacío es una mala idea porque estás tragando en silencio una condición de error y luego continúa la ejecución. Ocasionalmente esto puede ser lo correcto, pero a menudo es una señal de que un desarrollador vio una excepción, no sabía qué hacer al respecto y, por lo tanto, usó una captura vacía para silenciar el problema.

Es el equivalente de programación de poner cinta negra sobre una luz de advertencia del motor.

Creo que la forma en que maneje las excepciones depende de la capa del software en la que esté trabajando: excepciones en la selva .


Porque si se lanza una excepción, nunca la verá (si falla silenciosamente es la peor opción posible), obtendrá un comportamiento erróneo y no tendrá idea de dónde está pasando. ¡Por lo menos pon un mensaje de registro allí! ¡Incluso si es algo que "nunca puede suceder"!


Probablemente nunca sea lo correcto porque estás pasando silenciosamente todas las excepciones posibles. Si hay una excepción específica que está esperando, entonces debe probarla, vuelva a lanzar si no es su excepción.

try { // Do some processing. } catch (FileNotFound fnf) { HandleFileNotFound(fnf); } catch (Exception e) { if (!IsGenericButExpected(e)) throw; } public bool IsGenericButExpected(Exception exception) { var expected = false; if (exception.Message == "some expected message") { // Handle gracefully ... ie. log or something. expected = true; } return expected; }


Si no sabe qué hacer en catch block, puede registrar esta excepción, pero no la deje en blanco.

try { string a = "125"; int b = int.Parse(a); } catch (Exception ex) { Log.LogError(ex); }


Un bloque de catch vacío es esencialmente decir "No quiero saber qué errores se lanzan, voy a ignorarlos".

Es similar al On Error Resume Next VB6 On Error Resume Next , excepto que cualquier cosa en el bloque try después de que se lanza la excepción será omitida.

Lo cual no ayuda cuando algo se rompe.


En general, son una mala idea porque es una condición realmente rara en la que una falla (condición excepcional, más genéricamente) se satisface adecuadamente SIN respuesta alguna. Además de eso, los bloques de catch vacíos son una herramienta común utilizada por las personas que usan el motor de excepción para la comprobación de errores que deberían estar haciendo de manera preventiva.

Decir que siempre es malo no es cierto ... eso es cierto de muy poco. Puede haber circunstancias en las que no le importe que haya un error o que la presencia del error de alguna manera indique que no puede hacer nada al respecto de todos modos (por ejemplo, al escribir un error anterior en un archivo de registro de texto y obtienes una IOException , lo que significa que no puedes escribir el nuevo error de todos modos).