Uso correcto de las excepciones de Java

Tengo varias preguntas sobre el mejor uso de las excepciones en Java.

Considere el siguiente código:

private String doHttpGetRequest(String url) throws IOException {
...
}

private Photo processJson(String json) throws JSON Exception{
...
}

private Photo getPhoto() throws IOException, JSON Exception {
    String url = "http://...";
    String response = doHttpGetRequest(url);
    Photo photo = processJson(response);
    photo.downloadImage();
    return photo;
}

public static void main(String args[]) {
    Photo p = null; 
    try {
        p = getPhoto();
    } catch( JSONException j ) {
        // Re-try a few times, then display user alert
    } catch( IOException e ) {
        // Re-try a few times, then display user alert
    }

    if( p!=null)
        // now display photo
}

Este código es para una aplicación de Android donde la conexión puede no ser muy confiable, por lo que me gustaría volver a intentar el método getPhoto () varias veces para ver si funciona, luego fallar y alertar al usuario.

Mis preguntas:

  1. Estoy abriendo un InputStream en doHttpGetRequest () y ese método está lanzando una IOException. ¿Cómo cierro InputStream si ha lanzado la excepción? Sin un bloqueo final dentro del método que me permitiría cerrar recursos, estoy confundido.

  2. En main (), solo me interesa si getPhoto () funciona o no. ¿Sería mejor rodear las declaraciones dentro de getPhoto () con un bloque try / catch y capturar la JSONException, lanzando una nueva IOException cuando se detecta? Esto llevaría a tener que detectar solo un tipo de excepción en main (), lo que generaría un código más simple y no tendría una funcionalidad duplicada.

  3. Si p.getPhoto () arroja una excepción, quiero volver a intentarlo (posiblemente dos veces) y luego mostrar una alerta de usuario si esto falla. ¿Existe una estructura de programación común para hacer esto?

preguntado el 08 de noviembre de 11 a las 10:11

Si este es el código de la aplicación de Android, ¿por qué main ¿método? ¿O está escribiendo su código para el escritorio con la intención de portarlo a Android más tarde? -

Este es un código que es simplemente un código demostrativo para el propósito de la pregunta. -

3 Respuestas

  1. doHttpGetRequest() debe estar a cargo de cerrar el flujo de entrada. Finalmente, bloquear allí sería adecuado para cerrar (¿por qué no quieres bloquear finalmente?).

  2. ¿Tiene que pasar alguna excepción al método principal? Podrías rodear doHttpGetRequest(url) con try{} y rodear processJson con otro (creo que este no se beneficia de los reintentos). Esto haría que el main() limpiador de método.

  3. Si sigue mi sugerencia en 2. podría volver a intentarlo así:

    String response = null;
    for (int i = 0; i < RETRY_COUNT && response == null; i++){
      try {
        response = doHttpGetRequest(url);
      } catch (IOException e){
        // Possibly log the error here
      }
    }
    if (response  == null) return null;
    

EDITAR: corrección de errores

respondido 08 nov., 11:15

  1. Puede capturar la excepción, limpiarla y volver a lanzarla. ¿Por qué estás evitando usar finally ¿cuadra? Parece que encajaría muy bien allí.

  2. Probablemente será más código que manejar esas dos excepciones por separado.

  3. Ponlo en un for lazo, continue si hubo una excepción y break si no.

respondido 08 nov., 11:14

  1. Aún debe usar el bloqueo try-finalmente para poder cerrar los recursos. El bloque se usa así:

    InputStream is;
    try {
        is = openStream(); //This is a sample code, which 
        //Do something with the stream
    } finally {
        if (is != null) is.close();
    }
    

    De esta manera, si se lanza una excepción, la transmisión se cerrará de todos modos y la excepción se manejará en otro lugar.

  2. Le sugiero que cree su propia excepción (por ejemplo, PhotoReadingException) y la arroje desde getPhoto (), pero estableciendo su causa en la excepción original a través del initCause(Throwable cause) método.

  3. Ciertamente, puede usar un bucle y una variable que muestre si la operación fue exitosa.

    Photo p = null; 
    Exception ex = null;
    for (int tries = 0; tries < MAX_TRIES; tries++) {
        try {
            p = getPhoto();
            break;
        } catch (PhotoReadingException photoException) {
            ex = photoException;
        }
    }
    if (ex != null) reportException(ex);
    

respondido 08 nov., 11:16

La forma convencional de establecer la causa de una excepción es pasando la excepción de causa hacia arriba en la cadena del constructor. - Stephen C

@Stephen C Es posible si obtiene su excepción de java.lang.Exception. Sin embargo, IOException, por ejemplo, no tiene un constructor como el de Java 1.5. initCause sin embargo, todavía está disponible. Dado que el OP mencionó escribir una aplicación para Android, y Android anterior a 2.3 se basa en bibliotecas de Java 1.5, decidí mencionar una forma que siempre funciona. - Malcolm

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.