9 métodos de manejo de excepciones de Java comúnmente utilizados y convenientes para ayudarlo a salir del tedioso

Prefacio

El manejo de excepciones en Java no es un tema simple. Es difícil de entender para los principiantes, incluso los desarrolladores experimentados pueden pasar horas discutiendo cómo y qué excepciones deben lanzarse o manejarse.

Es por eso que la mayoría de los equipos de desarrollo tienen un conjunto de reglas sobre cómo usarlos. Y, si es nuevo en el equipo, se sorprenderá de lo diferentes que son estas reglas de las que usaba antes.

A pesar de esto, la mayoría de los equipos han adoptado varias mejores prácticas. Aquí están las 9 piezas de información más importantes que pueden ayudarlo a comenzar o mejorar el manejo de excepciones.


1. Limpiar recursos en el bloque finalmente o utilizar la instrucción Try-With-resource

A menudo sucede que usa un recurso en un bloque try, como InputStream, y luego necesita cerrarlo. En estos casos, un error común es cerrar el recurso al final del bloque try.

public void doNotCloseResourceInTry() {
    FileInputStream inputStream = null;
    try {
        File file = new File("./tmp.txt");
        inputStream = new FileInputStream(file);

        // use the inputStream to read a file

        // do NOT do this
        inputStream.close();
    } catch (FileNotFoundException e) {
        log.error(e);
    } catch (IOException e) {
        log.error(e);
    }
}

El problema es que este método parece funcionar bien siempre que no genere una excepción. Se ejecutarán todas las instrucciones del bloque try y se cerrarán los recursos.

Pero agrega el bloque try por una razón. Usted llama a uno o más métodos que pueden generar una excepción, o puede generar una excepción usted mismo. Esto significa que es posible que no haya llegado al final del bloque de prueba. Por lo tanto, no cerrará el recurso.

Por lo tanto, debe poner todo el código de limpieza en un bloque finalmente o usar una instrucción try-with-resource.

Utilice el módulo finalmente

Al contrario de las últimas líneas del bloque try, el bloque finalmente se ejecuta siempre. Esto sucede después de que el bloque try se ejecuta con éxito o después de que se maneja la excepción en el bloque catch. Por lo tanto, puede asegurarse de que se borren todos los recursos abiertos.

public void closeResourceInFinally() {
    FileInputStream inputStream = null;
    try {
        File file = new File("./tmp.txt");
        inputStream = new FileInputStream(file);

        // use the inputStream to read a file

    } catch (FileNotFoundException e) {
        log.error(e);
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                log.error(e);
            }
        }
    }
}

Otra opción para la declaración Try-With-Resource en Java 7 es la declaración try-with-resource, que expliqué en detalle en Introducción al manejo de excepciones de Java.

Si su recurso implementa la interfaz AutoCloseable, puede usarla. Eso es lo que hacen la mayoría de los recursos estándar de Java. Cuando abre un recurso en una cláusula try, el recurso se cerrará automáticamente después de que se ejecute el bloque try o se maneje una excepción.

public void automaticallyCloseResource() {
    File file = new File("./tmp.txt");
    try (FileInputStream inputStream = new FileInputStream(file);) {
        // use the inputStream to read a file

    } catch (FileNotFoundException e) {
        log.error(e);
    } catch (IOException e) {
        log.error(e);
    }
}

Dos, especifique la excepción específica

Cuanto más específica sea la excepción lanzada, mejor. Siempre tenga en cuenta que los colegas que no conocen su código, o que pueden no conocer su código en unos meses, deben llamar a su método y manejar la excepción.

Por lo tanto, asegúrese de proporcionarles la mayor cantidad de información posible. Esto hace que su API sea más fácil de entender. Como resultado, la persona que llama a su método podrá manejar mejor la excepción o evitarla mediante comprobaciones adicionales.

Por lo tanto, siempre intente encontrar la clase que mejor se adapte a su evento de excepción, por ejemplo, lance NumberFormatException en su lugar.

IllegalArgumentException。并避免引发不确定的Exception。

public void doNotDoThis() throws Exception {
    ...
}
public void doThis() throws NumberFormatException {
    ...
}

Resolvieron las preguntas de la entrevista clásicas reales para los ingenieros de Java en 2021, un total de 485 páginas de aproximadamente 850 preguntas de entrevista PDF con respuestas, que incluyen Java, MyBatis, ZooKeeper, Dubbo, Elasticsearch, Memcached, Redis, MySQL, Spring, Spring Boot, Spring Cloud, RabbitMQ, Kafka, Linux, etc. Casi todas las pilas de tecnología, cada pila de tecnología tiene no menos de 50 preguntas de entrevista clásicas. No me atrevo a decir que ingresará a una gran fábrica después de terminar el paquete, pero la aplicación específica le permitirá enfrentarse al entrevistador. Está bien tener un poco más de confianza cuando lo hace.

Tres, archivar excepciones específicas

Siempre que se especifique una excepción en la firma del método, también debe documentarse en el Javadoc. Esto tiene el mismo objetivo que las mejores prácticas anteriores: proporcionar a la persona que llama la mayor cantidad de información posible para que pueda evitar o manejar excepciones.

Por lo tanto, asegúrese de agregar una declaración @throws en el Javadoc y describa las circunstancias que pueden causar la excepción.

/**
 * This method does something extremely useful ...
 *
 * @param input
 * @throws MyBusinessException if ... happens
 */
public void doSomething(String input) throws MyBusinessException {
    ...
}

Cuatro, incluya información de descripción al lanzar una excepción

La idea detrás de las mejores prácticas es similar a las dos anteriores. Pero esta vez, no proporcionó la información a la persona que llamó de su método. Todas las personas que deben comprender el archivo de registro o lo que sucedió cuando se informó la excepción en su herramienta de monitoreo pueden leer el mensaje de la excepción.

Por lo tanto, debe describir el problema con la mayor precisión posible y proporcionar la información más relevante para comprender el evento anormal.

No me malinterpretes, no debes escribir un párrafo. Pero debe usar 1-2 oraciones cortas para explicar el motivo de la anomalía. Esto puede ayudar a su equipo de operaciones a comprender la gravedad del problema y también puede facilitarle el análisis de cualquier incidente de servicio.

Si se lanza una excepción específica, es posible que el nombre de la clase ya describa el tipo de error. Por lo tanto, no es necesario que proporcione mucha más información. Un buen ejemplo es NumberFormatException. Cuando proporcione un String en el formato incorrecto, el constructor de la clase java.lang.Long lo generará.

try {
    new Long("xyz");
} catch (NumberFormatException e) {
    log.error(e);
}

El nombre de la clase NumberFormatException ya le indica el tipo de problema. Su mensaje solo necesita proporcionar la cadena de entrada que causó el problema. Si el nombre de la clase de excepción no es tan expresivo, debe proporcionar la información requerida en el mensaje.

17:17:26,386 ERROR TestExceptionHandling:52 - java.lang.NumberFormatException: For input string: "xyz"

Cinco, captura la excepción más específica primero

La mayoría de los IDE pueden ayudarlo a obtener las mejores prácticas. Cuando intenta detectar primero excepciones menos específicas, informan de bloques de código inaccesibles.

El problema es que solo se ejecuta el primer bloque catch que coincide con la excepción. Por lo tanto, si detecta IllegalArgumentException primero, nunca llegará al bloque de captura que debería manejar la NumberFormatException más específica, porque es una subclase de IllegalArgumentException.

Capture siempre primero la clase de excepción más específica y agregue el bloque de captura menos específico al final de la lista.

Puede ver un ejemplo de dicha declaración try-catch en el siguiente fragmento de código. El primer bloque catch maneja todas las NumberFormatException , el segundo todas las IllegalArgumentException , no son NumberFormatException .

public void catchMostSpecificExceptionFirst() {
    try {
        doSomething("A message");
    } catch (NumberFormatException e) {
        log.error(e);
    } catch (IllegalArgumentException e) {
        log.error(e)
    }
}

Seis, no atrapes la excepción Throwable

Throwable es la superclase de todas las excepciones y errores. Puede usarlo en la cláusula catch, ¡pero nunca lo haga!

Si usa Throwable en la cláusula catch, no solo capturará todas las excepciones, sino también todas las Excepciones. También detectará todos los errores. La JVM genera serios problemas de error que la aplicación no manejará.

Por ejemplo: OutOfMemoryError o StackOverflowError.

Ambos son causados ​​por circunstancias fuera del control de la aplicación y no pueden manejarse.

Por lo tanto, es mejor no capturar Throwable a menos que esté absolutamente seguro de que se encuentra en una situación especial, en cuyo caso puede o debe manejar los errores.

public void doNotCatchThrowable() {
    try {
        // do something
    } catch (Throwable t) {
        // don't do this!
    }
}

Siete, no ignores las excepciones

¿Alguna vez ha analizado un informe de error que se ejecutó solo en la primera parte del caso de uso?

Esto suele deberse a una excepción pasada por alto. El desarrollador puede estar bastante seguro de que no se lanzará y agregará un bloque de captura que no lo procesará ni lo registrará. Y, cuando encuentre el bloque, lo más probable es que incluso haya encontrado uno de los famosos comentarios de "Esto nunca sucederá".

public void doNotIgnoreExceptions() {
    try {
        // do something
    } catch (NumberFormatException e) {
        // this will never happen
    }
}

Bueno, puede que estés analizando un problema imposible.

Por lo tanto, no ignore la excepción. No sabe cómo cambiará el código en el futuro. Alguien puede eliminar la verificación que previene eventos anómalos sin darse cuenta de que causará problemas. O bien, el código que causó la excepción se ha cambiado y ahora se generan varias excepciones de la misma clase, y el código de llamada no puede evitar todas estas excepciones.

Debería al menos escribir un mensaje de registro para decirle a todo el mundo que lo impensable acaba de suceder y que alguien debe comprobarlo.

public void logAnException() {
    try {
        // do something
    } catch (NumberFormatException e) {
        log.error("This should never happen: " + e);
    }
}

8. No grabe y lance

Esta es probablemente la mejor práctica que se pasa por alto con mayor frecuencia en esta lista. Puede encontrar muchos fragmentos de código e incluso bibliotecas que detectan, registran y vuelven a generar excepciones.

try {
    new Long("xyz");
} catch (NumberFormatException e) {
    log.error(e);
    throw e;
}

Puede resultar intuitivo registrar la excepción que se produjo y luego volver a lanzarla para que la persona que llama pueda manejarla adecuadamente. Pero escribirá varios mensajes de error para la misma excepción.

17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"
Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.(Long.java:965)
at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)
在com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)

No se agregará información a otros mensajes. Como se describe en la Mejor Práctica 4, el mensaje de excepción debe describir el evento inusual. El seguimiento de la pila le dirá en qué clase, método y línea se lanzó la excepción.

Si necesita agregar información adicional, debe capturar la excepción y envolverla en una excepción personalizada. Pero asegúrese de seguir las mejores prácticas 9.

public void wrapException(String input) throws MyBusinessException {
    try {
        // do something
    } catch (NumberFormatException e) {
        throw new MyBusinessException("A message that describes the error.", e);
    }
}

Por lo tanto, solo detecte excepciones cuando desee manejarlo. De lo contrario, especifíquelo en la firma del método y deje que la persona que llama lo maneje.

Nueve, anomalías en el empaque sin consumir anomalías

A veces es mejor capturar una excepción estándar y envolverla en una excepción personalizada. Los ejemplos típicos de tales excepciones son las excepciones comerciales específicas para aplicaciones o marcos. Esto le permite agregar información adicional y también implementar un manejo especial para clases de excepción.

Al hacer esto, asegúrese de establecer la excepción original como causa. La clase de excepción proporciona un Throwable que acepta un constructor específico como parámetro. De lo contrario, perderá el seguimiento de la pila y el mensaje de excepción original, lo que dificultará el análisis del evento de excepción que provocó su excepción.

public void wrapException(String input) throws MyBusinessException {
    try {
        // do something
    } catch (NumberFormatException e) {
        throw new MyBusinessException("A message that describes the error.", e);
    }
}

para resumir

En resumen, al lanzar o capturar una excepción, debe considerar muchas cosas diferentes. El objetivo de la mayoría de ellos es mejorar la legibilidad del código o la usabilidad de la API.

Las excepciones suelen ser los mecanismos de manejo de errores y los medios de comunicación que existen al mismo tiempo. Por lo tanto, debe asegurarse de discutir las mejores prácticas y reglas que se aplicarán con sus colegas para que todos puedan comprender los conceptos generales y usarlos de la misma manera.

Supongo que te gusta

Origin blog.csdn.net/fly1north/article/details/115217917
Recomendado
Clasificación