Pregunta Generando error fatal en Java


Supongamos que estamos escribiendo una biblioteca Java, que proporciona algunas funciones de I / O ulitity, por ejemplo, un método conveniente para leer archivos de texto como cadenas:

public class StringReader {

private static final Logger log = LoggerFactory.getLog(StringReader.class);

/**
 * Returns the contents of file <b>fileName</b> as String.
 * @param fileName file name to read
 * @return null on IO error
 */
public static String readString(String fileName) {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(fileName);
        byte[] data = new byte[fis.available()];
        fis.read(data);
        return new String(data, "ISO-8859-1"); // may throw UnsupportedEncodingException!
    } catch (IOException e) {
        log.error("unable to read file", e);
    } catch (UnsupportedEncodingException e) {
        log.fatal("JRE does not support ISO-8859-1!", e);
        // ???
    } finally {
        closeQuiet(fis);
    }

    return null;
}
}

Este código lee un archivo de texto en una cadena usando la codificación ISO-8859-1 y devuelve la cadena al usuario.

los String(byte[], String) constructor lanza una UnsupportedEncodingException cuando la codificación especificada no es compatible. Pero, como sabemos, ISO-8859-1 debe ser respaldado por JRE, como se dijo aquí (ver el Juegos de caracteres estándar sección).

Por lo tanto, esperamos que el bloque.

catch (UnsupportedEncodingException e) {
    log.fatal("encoding is unsupported", e);
    // ???
}

Nunca se alcanza si la distribución de JRE cumple con el estándar.

Pero, ¿y si no? ¿Cómo manejar esta excepción de la manera más correcta? La pregunta es, ¿cómo alertar adecuadamente sobre tal error?

Las sugerencias son:

  1. Lanza algún tipo de RuntimeException.
  2. No deshabilite el registrador en el código de producción, escriba los detalles de una excepción en el registro e ignórelo.
  3. Pon el assert false aquí, para que produzca AssertionError si el usuario lanzó VM con -ea.
  4. Lanza un AssertionError a mano.
  5. Añadir un UnsupportedEncodingException en declaración de método y permite al usuario elegir. No es muy conveniente, creo.
  6. Llamada System.exit(1).

Gracias.


5
2017-10-29 07:00


origen


Respuestas:


Pero, ¿y si no?

Entonces estás en una situación realmente mala, y probablemente deberías salir de ella lo más rápido posible. Cuando un JRE está violando sus propias promesas, ¿qué haría quieres depender?

Me sentiría feliz de usar AssertionError en este caso.

Es importante tener en cuenta que no todas las excepciones sin marcar son tratadas por igual, no es inusual que el código capte Exception en el nivel superior de la pila, registre un error y luego continúe ... si acaba de lanzar RuntimeException, ese será ser atrapado por tal esquema. AssertionError solo se atraparía si el bloque catch especifica Throwable (o específicamente Error o AssertionError, pero eso es mucho más raro de ver). Dado lo imposible que debería ser, creo que es razonable abortar muy duro.

También tenga en cuenta que en Java 7, puede utilizar StandardCharsets.ISO_8859_1 en lugar del nombre de la cadena, que es más limpio y elimina el problema.

Hay otras cosas que cambiaría sobre su código, por cierto:

  • Yo evitaría usar available() tan lejos como sea posible. Eso te dice cuántos bytes están disponibles ahora mismo - No te dice cuánto tiempo tiene el archivo, necesariamente.
  • me gustaría seguro No asuma que read() leerá todo el archivo de una vez. Llamada read() en un bucle, idealmente hasta que dice que no hay más datos.
  • Yo personalmente acepto una Charset como un parámetro, en lugar de la codificación ISO-8859-1. - Dejaría IOException burbujear desde el método en lugar de simplemente regresar null. Después de todo, a menos que estés De Verdad va a verificar el valor de retorno de cada llamada de nulidad, solo va a terminar con un NullPointerException en su lugar, que es más difícil de diagnosticar que el original IOException.

Alternativamente, solo usa Guayabaes Files.toString(File, Charset) para empezar :) (Si aún no está usando guayaba, ahora es un buen momento para comenzar ...)


7
2017-10-29 07:04



Esta es una ocurrencia bastante común en el código.

Las excepciones no verificadas están hechas para esto. No deberían ocurrir (por lo que no están controlados), pero si lo hacen, todavía hay una excepción.

Entonces, tira un RuntimeException que tiene el original Exception como la causa

catch (UnsupportedEncodingException e) {
    throw new RuntimeException(e); //should not happen
}

assert(false); también lanza una excepción no verificada, pero las aserciones se pueden desactivar, por lo que recomendaría RuntimeException.


4
2017-10-29 07:03