Fuga de recursos: 'in' nunca se cierra


84

¿Por qué Eclipse me da la advertencia "Fuga de recursos: 'in' nunca se cierra" en el siguiente código?

public void readShapeData() {
        Scanner in = new Scanner(System.in);
        System.out.println("Enter the width of the Rectangle: ");
        width = in.nextDouble();
        System.out.println("Enter the height of the Rectangle: ");
        height = in.nextDouble();

Respuestas:


69

Porque no cierra su escáner

in.close();

39
Esto cerrará Scannery silenciará la advertencia, pero también cerrará, lo System.inque normalmente no es deseable.
Stuart Cook

@StuartCook +1. Algo que vigilar.
informatik01

7
¿Por qué necesitamos cerrar Scanner? ¿Qué se entiende por "fuga de recursos"?
Erran Morad

1
@nogard: esta su respuesta es realmente útil ... pero cuando uso in.close (); .. nuevamente se muestra que no se puede resolver .. tengo un código sin manejo de excepciones .. gracias
pcs

3
@StuartCook, olvidó mencionar por qué el cierre System.ingeneralmente no es deseable. Es porque no podrás volver a leerlo. I. e. obtendrá java.util.NoSuchElementException: No line foundsi intenta llamar, (new Scanner(System.in)).nextLine()por ejemplo.
Petr Bodnár

55

Como han dicho otros, debe llamar a "cerrar" en las clases de IO. Agregaré que este es un excelente lugar para usar el intento, finalmente bloquear sin captura, como este:

public void readShapeData() throws IOException {
    Scanner in = new Scanner(System.in);
    try {
        System.out.println("Enter the width of the Rectangle: ");
        width = in.nextDouble();
        System.out.println("Enter the height of the Rectangle: ");
        height = in.nextDouble();
    } finally {
        in.close();
    }
}

Esto asegura que su escáner esté siempre cerrado, garantizando una limpieza adecuada de los recursos.

De manera equivalente, en Java 7 o superior, puede utilizar la sintaxis "try-with-resources":

try (Scanner in = new Scanner(System.in)) {
    ... 
}

2
¿Qué se entiende por fuga de recursos y cómo me afectará?
Erran Morad

7
@Borat - "pérdida de recursos" implica que algún recurso del sistema (generalmente memoria) se está perdiendo o desperdiciando innecesariamente. Por lo general, esto lo afectará cuando comience a generar OutOfMemoryErrors durante el funcionamiento normal de su programa.
Eric Lindauer

Gracias eric. Sé que puede causar el error agregando una cadena a sí mismo en un bucle infinito. No estoy seguro de cómo un escáner podría causar ese error.
Erran Morad

4
¿Qué tal una prueba con recursos?
Dennis Meng

Gracias Dennis, añadió.
Eric Lindauer

12

Necesita llamar in.close(), en un finallybloque para asegurarse de que ocurra.

De la documentación de Eclipse, he aquí por qué señala este problema en particular (el énfasis es mío):

Se considera que las clases que implementan la interfaz java.io.Closeable (desde JDK 1.5) y java.lang.AutoCloseable (desde JDK 1.7) representan recursos externos, que deben cerrarse usando el método close (), cuando ya no se necesiten.

El compilador de Eclipse Java puede analizar si el código que utiliza estos tipos se adhiere a esta política.

...

El compilador marcará [violaciones] con "Pérdida de recursos: 'flujo' nunca se cierra".

Explicación completa aquí .


7

Se le está diciendo que necesita cerrar el escáner que ejemplarizado en System.inla Scanner.close(). Normalmente, todos los lectores deben estar cerrados.

Tenga en cuenta que si cierra System.in, no podrá volver a leerlo. También puede echar un vistazo a la Consoleclase.

public void readShapeData() {
    Console console = System.console();
    double width = Double.parseDouble(console.readLine("Enter the width of the Rectangle: "));
    double height = Double.parseDouble(console.readLine("Enter the height of the Rectangle: "));
    ...
}

3
Tenga en cuenta que System.console()no está disponible cuando se ejecuta una aplicación a través de Eclipse, lo que puede resultar complicado durante el desarrollo.
Stuart Cook

6

Si está usando JDK7 u 8, puede usar try-catch con recursos. Esto cerrará automáticamente el escáner.

try ( Scanner scanner = new Scanner(System.in); )
  {
    System.out.println("Enter the width of the Rectangle: ");
    width = scanner.nextDouble();
    System.out.println("Enter the height of the Rectangle: ");
    height = scanner.nextDouble();
  }
catch(Exception ex)
{
    //exception handling...do something (e.g., print the error message)
    ex.printStackTrace();
}

Tenga en cuenta que la cláusula de captura no es obligatoria. Si solo desea asegurarse de que el recurso esté cerrado incluso en el caso de una excepción, pero deje el tratamiento de las excepciones como en el código original del OP (es decir, no detectado en absoluto) puede usarlo trycomo se muestra y no usar una catchcláusula.
user118967

5
// An InputStream which is typically connected to keyboard input of console programs

Scanner in= new Scanner(System.in);

La línea anterior invocará al Constructor de la clase Scanner con el argumento System.in, y devolverá una referencia al objeto recién construido.

Está conectado a un flujo de entrada que está conectado al teclado, por lo que ahora, en tiempo de ejecución, puede tomar la entrada del usuario para realizar la operación requerida.

//Write piece of code 

Para eliminar la pérdida de memoria:

in.close();//write at end of code.


3

agregar private static Scanner in;realmente no soluciona el problema, solo borra la advertencia. Hacer que el escáner sea estático significa que permanece abierto para siempre (o hasta que se descargue la clase, lo que casi es "para siempre"). El compilador ya no le da más advertencia, ya que le dijo "manténgalo abierto para siempre". Pero eso no es lo que realmente deseaba, ya que debería cerrar los recursos tan pronto como ya no los necesite.

HTH, Manfred.


2

Generalmente, las instancias de clases que se ocupan de E / S deben cerrarse una vez que haya terminado con ellas. Entonces, al final de su código, podría agregar in.close().


2
private static Scanner in;

Lo arreglé declarando como una variable de clase de escáner estática privada. No estoy seguro de por qué eso lo solucionó, pero eso es lo que eclipse recomendó que hiciera.


5
silenció la advertencia pero creó una fuga de recursos
zacheusz

1

El escáner debe estar cerrado. Es una buena práctica cerrar Readers, Streams ... y este tipo de objetos para liberar recursos y ávidas pérdidas de memoria; y hacerlo en un bloque final para asegurarse de que estén cerrados incluso si se produce una excepción al manipular esos objetos.


Esta respuesta realmente ayuda a OP a saber por qué debería cerrar la cosa. Claro, puede leer el documento y ver " scanner.close()", pero esta respuesta realmente le ayuda a entender lo que está pasando. + 1
HyperNeutrino

1

De acuerdo, en serio, al menos en muchos casos, esto es en realidad un error. También aparece en VS Code, y el linter se da cuenta de que ha alcanzado el final del alcance adjunto sin cerrar el objeto del escáner, pero sin reconocer que cerrar todos los descriptores de archivos abiertos es parte de la terminación del proceso. No hay pérdida de recursos porque todos los recursos se limpian al finalizar, y el proceso desaparece, sin dejar ningún lugar para que el recurso se mantenga.


0
Scanner sc = new Scanner(System.in);

//do stuff with sc

sc.close();//write at end of code.

-1
in.close();
scannerObject.close(); 

Cerrará Scannery cerrará la advertencia.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.