2010-03-22 19 views
5

¿Es una buena práctica establecer las referencias de flujo a nulo después de cerrarlas? ¿Esto liberaría recursos de alguna manera?Java: hacer referencia nulo después de cerrar la secuencia

Ejemplo:

BufferedReader input= new BufferedReader(new FileReader("myfile.txt")); 

// code 

input.close(); 
input = null; 

// possible more code 
+0

@Hei: Bienvenido a SO. Solo para el futuro (y si edita esta pregunta), puede sangrar líneas de código con cuatro espacios y se mostrarán en bloques de códigos especiales, lo que hace que sean más fáciles de leer. – Pops

+0

Gracias por el comentario lo investigaré para futuras preguntas. – Hei

Respuesta

6

No, es una mala práctica. OMI, incluso debería considerar hacer la variable final.

El manejo de recursos se debe manejar de la manera estándar acquire(); try { use(); } finally { release(); }. En este caso:

final Reader rawIn = new FileReader("myfile.txt"); // Character encoding?? 
try { 
    BufferedReader in = new BufferedReader(rawIn); 

    // code 

} finally { 
    rawIn.close(); 
} 

En realidad, este código selecciona la codificación de caracteres que está configurada por defecto. Sugiero ser explícito con un conjunto de caracteres codificados o con Parameterise from Above.

final InputStream rawIn = new FileInputStream("myfile.txt"); 
try { 
    BufferedReader in = new BufferedReader(
     new InputStreamReader(rawIn, "UTF-8") 
    ); 

    // code 

} finally { 
    rawIn.close(); 
} 

No debe crear los flujos de envoltura/lectores de fuera del bloque try (y antes de la asignación de recursos), ya que podría lanzar. Del mismo modo, su cierre podría arrojar (esto fue en realidad un error en BufferedOutputStream que podría lanzar en flush). Algunas secuencias de entrada pueden tener otros recursos, por lo que necesita dos try { ... finally { x.close(); } s.

Para la salida, generalmente debe flush en el curso normal de los eventos. Pero generalmente no en casos excepcionales. De hecho close generalmente hace un flush, por lo tanto, no debe cerrarlos en el caso excepcional. Si decoradores ambos flush y tienen recursos, entonces tendrá que sonreír y mostrarlo.

Hay ocasiones muy infrecuentes en que anular es una buena idea. Por ejemplo, si una variable es la única referencia a un objeto grande y va a crear un nuevo objeto grande para asignarle, puede ser mejor borrar la referencia para permitir que se recupere la antigua antes de asignar la nueva.

+5

+1 para usar 'final' en la declaración de flujo. -1 para cerrar la secuencia interna ('rawIn'). Siempre debe cerrar la secuencia más derivada. Por ejemplo, en su caso 'BufferedReader' puede tener algunos datos en su búfer interno. Llamar de cerca en 'in' vaciará correctamente estos datos. Llamando cerca de 'rawIn' lo descartará. –

+0

Gracias por la respuesta y por mencionar un caso en el que anular sería una buena idea. – Hei

+0

@Alexander Pogrebnyak No. Agregaré una edición. –

5

No es necesario. Solo input.close() es suficiente. Recuerde que siempre es aconsejable hacerlo dentro de un bloque finally. Y antes de llamar a su close() mejor que hacer un cheque nulo como esto

finally{ 
    if(input!=null){ 
    input.close(); 
    } 
} 
+3

Si realiza la asignación original * antes * del bloque try, no necesita la verificación de nulidad. Solo fallará si el archivo no se puede abrir, en cuyo caso no hay problema de todos modos. –

1

A menos que estés administración manual de un charco de rosources (el manejo de su propia memoria), no es necesario anular el flujo de entrada. Idealmente, cualquiera que sea la función en la que se encuentre es pequeña, y las referencias al objeto morirán a medida que el objeto salga del alcance, marcándolo de todos modos para la recolección de elementos no utilizados.

Menciono los recursos de la agrupación, como si ingenuamente cerrara la secuencia sin anular el objeto, podría retener accidentalmente una referencia del objeto que realmente no necesita.

3

Se puede hacer que el objeto Stream sí aptos para reciclaje, pero

  1. En la mayoría de los casos va a pasar fuera de alcance justo después de todos modos
  2. la cantidad de memoria por lo tanto "liberado" es completamente insignificante
+0

Bueno, no de inmediato. Tendrá que pasar por la finalización antes de que se libere la memoria en una colección posterior. –

0

En este caso no es necesario, el recolector de basura lo recogerá.

Pero no siempre es una mala práctica asignar null. Leer el artículo 6 de Effective Java, chapter 2

1

No, no lo es. El close() ya libera el recurso. La práctica habitual es la siguiente:

Resource resource = null; 
try { 
    resource = new Resource(); 
    // ... 
} finally { 
    if (resource != null) try { resource.close(); } catch (ResourceException logOrIgnore) {} 
} 

Dónde Resource puede ser cualquier recurso externo desea utilizar, como InputStream, OutputStream, Reader y Writer de API de Java IO, sino también, por ejemplo, Connection, y StatementResultSet de API JDBC.

La memoria no es un problema en un código bien diseñado. Si el código deja el bloque de método, ya es elegible para GC.

Puede refactorizar el close() a un método de utilidad como:

public static void close(Closeable resource) { 
    if (resource != null) { 
     try { 
      resource.close(); 
     } catch (ResourceException logOrIgnore) { 
      // Log it? 
     } 
    } 
} 

que se puede utilizar de la siguiente manera:

} finally { 
    close(resource); 
} 

El Apache Commons proporciona varios métodos de utilidad por el estilo.

+0

O puede colocar la adquisición de recursos en el lugar correcto w.r.t. el 'intento' –

+0

Punto justo, pero a veces le gustaría capturar, registrar y volver a lanzar la excepción en el mismo bloque 'try', si es necesario como otro tipo de excepción. – BalusC

+1

¡Empuja el bote! ¡Usa dos bloques 'try'! Y luego usa la expresión Ejecutar Alrededor. –

Cuestiones relacionadas