Pregunta

Está bien, he estado haciendo lo siguiente (se han cambiado los nombres de las variables):


FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...

}
catch (IOException e)
{
    ... handle error ...
}
finally
{
    if (fis != null)
        fis.close();
}

Recientemente, comencé a usar FindBugs, lo que sugiere que no estoy cerrando correctamente las secuencias. Decido ver si hay algo que se pueda hacer con un bloque final {}, y luego veo, oh sí, close () puede lanzar IOException. ¿Qué se supone que hace la gente aquí? Las bibliotecas de Java arrojan demasiadas excepciones comprobadas.

¿Fue útil?

Solución

Para Java 7 y superior try-with-resources debe ser utilizado:

try (InputStream in = new FileInputStream(file)) {
  // TODO: work
} catch (IOException e) {
  // TODO: handle error
}

Si estás atascado en Java 6 o inferior ...

Este patrón evita cometer errores con null :

    try {
        InputStream in = new FileInputStream(file);
        try {
            // TODO: work
        } finally {
            in.close();
        }
    } catch (IOException e) {
        // TODO: error handling
    }

Para obtener más detalles sobre cómo tratar con cerrar de manera efectiva, lea esta publicación del blog: Java: cómo no hacer un lío en el manejo de la corriente . Tiene más código de muestra, más profundidad y cubre los inconvenientes de envolver cerrar en un bloque captura .

Otros consejos

Algo como lo siguiente debería hacerlo, depende de usted si lanza o traga la excepción IOException al intentar cerrar la secuencia.

FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...


}
catch (IOException e)
{
    ... blah blah blah ...
}
finally
{
    try
    {
        if (fis != null)
            fis.close();
    }
    catch (IOException e)
    {
    }
}

Puede usar try- with-resources característica agregada JDK7. Fue creado precisamente para hacer frente a este tipo de cosas.

static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

La documenación dice:

  

La declaración try-with-resources asegura que cada recurso está cerrado   al final de la declaración.

También puedes usar un método simple de ayuda estática:

public static void closeQuietly(InputStream s) {
   if (null == s) {
      return;
   }
   try {
      s.close();
   } catch (IOException ioe) {
      //ignore exception
   }
}

y usa esto de tu bloque finalmente.

No hay mucho que agregar, excepto por una sugerencia estilística muy pequeña. El ejemplo canónico de código de autodocumentación se aplica en este caso; asigne un nombre de variable descriptivo a la IOException ignorada que debe capturar en close () .

Entonces, la respuesta de squiddle se convierte en:

public static void closeQuietly(InputStream s) {
   try {
      s.close();
   } catch (IOException ignored) {
   }
}

En la mayoría de los casos, creo que es mejor no capturar las excepciones de E / S, y simplemente usar intentar-finalmente:

final InputStream is = ... // (assuming some construction that can't return null)
try {
    // process is
    ...
} finally {
    is.close();
}

A excepción de FileNotFoundException , generalmente no puede " solucionar el problema " una IOException . Lo único que queda por hacer es informar un error, y normalmente lo manejarás más arriba en la pila de llamadas, por lo que me parece mejor propagar la excepción.

Dado que IOException es una excepción marcada, deberá declarar que este código (y cualquiera de sus clientes) lanza IOException . Puede que sea demasiado ruidoso o que no quiera revelar los detalles de la implementación del uso de IO. En ese caso, puede envolver todo el bloque con un controlador de excepciones que contenga la IOException en una RuntimeException o un tipo de excepción abstracta.

Detalle: Soy consciente de que el código anterior anula cualquier excepción del bloque try cuando la operación close en el finalmente El bloque produce una IOException . No creo que sea un gran problema: en general, la excepción del bloque try será la misma IOException que hace que el close falla (es decir, es bastante raro que IO funcione bien y luego falle en el punto de cierre). Si esto es una preocupación, podría valer la pena el " silencio " el cierre.

La siguiente solución lanza correctamente una excepción si el cierre falla sin ocultar una posible excepción antes del cierre.

try {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
} catch(IOException exc) {
    // kernel panic
}

Esto funciona porque las llamadas se cierran por segunda vez no tiene efecto .

Esto se basa en la guayaba , pero uno puede escribir su propio método close Quietly si se prefiere, como se muestra en squiddle (consulte también serg10 ).

Informar sobre un error de cierre, en el caso general, es importante porque el cierre podría escribir algunos bytes finales en el flujo, por ejemplo. debido al almacenamiento en búfer. Por lo tanto, su usuario quiere saber si falló, o probablemente quiera actuar de alguna manera. Por supuesto, esto podría no ser cierto en el caso específico de un FileInputStream, no lo sé (pero por las razones ya mencionadas, creo que es mejor informar un error de cierre si ocurre de todos modos).

El código anterior es un poco difícil de comprender debido a la estructura de los bloques de prueba incrustados. Podría considerarse más claro con dos métodos, uno que lanza una excepción IOException y otro que lo atrapa. Al menos eso es por lo que optaría.

private void work() throws IOException {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
}

public void workAndDealWithException() {
    try {
        work();
    } catch(IOException exc) {
        // kernel panic
    }
}

Basado en http : //illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html (referenciado por McDowell).

Esperemos que obtengamos cierres en Java algún día, y luego perderemos mucha verbosidad.

Entonces, en lugar de eso, habrá un método auxiliar en algún lugar de javaIO que puedas importar, probablemente tomará un " Closable " Interfaz y también un bloque. Dentro de ese método auxiliar, la captura try {closable.close ()} (IOException ex) {// blah} se define de una vez por todas, y luego podrá escribir

 Inputstream s = ....;
 withClosable(s) {
    //your code here
 }

¿Está preocupado principalmente por obtener un informe limpio de FindBugs o por tener un código que funcione? Estos no son necesariamente lo mismo. Su código original está bien (aunque me gustaría deshacerme del si (fis! = Null) redundante, ya que de lo contrario se habría lanzado una OutOfMemoryException ). FileInputStream tiene un método finalizador que cerrará la transmisión por usted en el caso poco probable de que reciba una excepción IOException en su procesamiento. Simplemente no vale la pena molestarse en hacer que su código sea más sofisticado para evitar el escenario extremadamente improbable de

  1. obtienes una excepción IOException y
  2. esto sucede tan a menudo que empiezas a tener problemas de atrasos en el finalizador.

Editar: si está recibiendo tantas IOExceptions que tiene problemas con la cola del finalizador, ¡tiene un pez mucho más grande que freír! Se trata de obtener un sentido de perspectiva.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top