2012-06-29 8 views
21

tengo el siguiente fragmento de código en un bloque try/catchInputStreams de cierre en Java

InputStream inputstream = conn.getInputStream(); 
InputStreamReader inputstreamreader = new InputStreamReader(inputstream); 
BufferedReader bufferedreader = new BufferedReader(inputstreamreader); 

Mi pregunta es que cuando tengo que cerrar estas corrientes en el bloque finally, tengo que cerrar toda la 3 secuencias o simplemente cerrando el befferedreader cerrará todas las demás transmisiones?

+1

Posible duplicado de [¿Debo cerrar() tanto FileReader como BufferedReader?] (Http://stackoverflow.com/questions/1388602/do-i-need-to-close-both-filereader-and-bufferedreader) – River

Respuesta

24

Por convención, las corrientes de envoltura (que envuelven las secuencias existentes) cierran la secuencia subyacente cuando están cerradas, por lo que solo debe cerrar bufferedreader en su ejemplo. Además, normalmente es inofensivo cerrar una transmisión ya cerrada, por lo que cerrar las 3 secuencias no hará daño.

+0

No puede garantizar que una implementación de flujo no genere una excepción al cerrarla si ya está cerca. Entonces, es mucho mejor seguir el camino correcto y cerrar solo el BufferedReader – Soronthar

+1

@Soronthar. Entonces esta implementación de flujo no es válida por contrato, que establece 'Si la transmisión ya está cerrada, invocar este método no tiene efecto. Todas las implementaciones válidas DEBEN comportarse así Es totalmente legítimo (y común) cerrar una transmisión ya cerrada. Normalmente lo cierras por primera vez en try-block y por segunda vez en el bloque finally donde cerrar en try-block te da la oportunidad de reaccionar ante la excepción y cerrar en finally block es para asegurar el cierre. –

+0

@FabianBarney tienes razón, olvidé que actualizaron las transmisiones con la interfaz de Closeable en JSE 6. – Soronthar

0

Como regla general, debe cerrar todo en el orden inverso al que los abrió.

0

Los cerraría todos en el orden inverso desde el que los había abierto, como si al abrirlos empujara el lector a una pila y el cierre extrajera el lector de la pila.

Al final, después de cerrar todo, la "pila del lector" debe estar vacía.

+0

¿Cuál es el motivo de esta recomendación? Cuando se especifican las secuencias de entrada filtradas y los lectores para cerrar la secuencia anidada en close()? – EJP

+0

Solo sentido común, supongo. Hay mejores respuestas en este hilo, como muestran los votos. Algunos incluso han mostrado el código fuente de la biblioteca. –

3

Cerrar el más externo es suficiente (es decir, BufferedReader). La lectura de la source code of BufferedReader podemos ver que cierra el interior Reader cuando se llama a su propia cerrar:

513  public void close() throws IOException { 
514   synchronized (lock) { 
515    if (in == null) 
516     return; 
517    in.close(); 
518    in = null; 
519    cb = null; 
520   } 
521  } 
522 } 
0

Sólo tiene que cerrar el recurso real. Debe cerrar el recurso incluso si falla la construcción de decoradores. Para la salida, debe enjuagar el objeto más decorador en el caso feliz.

Algunas complicaciones:

  • A veces los decoradores son diferentes recursos (algunas implementaciones de compresión utilizan el montón C).
  • Los decoradores de cierre en casos tristes causan en realidad sofocos, con la consiguiente confusión, como no cerrar realmente el recurso subyacente.
  • Parece que su recurso subyacente es URLConnection, que no tiene un método disconnect/close como tal.

Quizás desee considerar utilizar la expresión Ejecutar Alrededor para que no tenga que duplicar este tipo de cosas.

4

Normalmente, solo se puede cerrar la secuencia más externa, ya que, por convención, debe dispararse cerca de las secuencias subyacentes.

Así que normalmente código es el siguiente:

BufferedReader in = null; 

try { 
    in = new BufferedReader(new InputStreamReader(conn.getInputStream())); 
    ... 
    in.close(); // when you care about Exception-Handling in case when closing fails 
} 
finally { 
    IOUtils.closeQuietly(in); // ensure closing; Apache Commons IO 
} 

Sin embargo puede haber casos excepcionales en los que un constructor de flujo subyacente genera una excepción en los que ya se abrió la corriente. En ese caso, el código anterior no cerrará la secuencia subyacente porque el constructor externo nunca se llamó y in es nulo. Entonces el bloque final no cierra nada dejando la secuencia subyacente abierta.

Desde Java 7 se puede hacer esto:

try (OutputStream out1 = new ...; OutputStream out2 = new ...) { 
     ... 
     out1.close(); //if you want Exceptions-Handling; otherwise skip this 
     out2.close(); //if you want Exceptions-Handling; otherwise skip this    
    } // out1 and out2 are auto-closed when leaving this block 

En la mayoría de los casos que no desea de control de excepciones cuando se eleva al cerrar así que evita estos explícita estrecha() llama.

Editar Aquí hay un código para los no creyentes donde es importante usar este patrón. También puede leer Apache Commons IOUtils javadoc sobre el método closeQuietly().

OutputStream out1 = null; 
    OutputStream out2 = null; 

    try { 
     out1 = new ...; 
     out2 = new ...; 

     ... 

     out1.close(); // can be skipped if we do not care about exception-handling while closing 
     out2.close(); // can be skipped if we ... 
    } 
    finally { 
     /* 
     * I've some custom methods in my projects overloading these 
     * closeQuietly() methods with a 2nd param taking a logger instance, 
     * because usually I do not want to react on Exceptions during close 
     * but want to see it in the logs when it happened. 
     */ 
     IOUtils.closeQuietly(out1); 
     IOUtils.closeQuietly(out2); 
    } 

Usando @ "consejos" de Tom dejará out1 abrió cuando la creación de out2 genera una excepción. Este consejo es de alguien que habla de It's a continual source of errors for obvious reasons. Bueno, puedo ser ciego, pero no es obvio para mí. Mi patrón es a prueba de idiotas en cada caso de uso en el que pueda pensar, mientras que el patrón de Tom es propenso a errores.

+0

Por favor, no hagas ese tipo de baile 'nulo'. Es una fuente continua de errores por razones obvias. Y qué desastre. –

+1

Este es el patrón normal. ¿Qué más quieres hacer? –

+0

'acquire(); prueba {use(); } finally {release(); } ' –