¿Por qué y Cómo Cerrar Correctamente un Scanner en Java?
1. Introducción
Cuando utilizamos la clase Scanner de Java para leer entradas desde System.in, algunos IDEs pueden advertir sobre una posible fuga de recursos. Por ejemplo, si no cerramos explícitamente un Scanner, podríamos encontrarnos con una advertencia como “Resource leak: ‘scanner’ is never closed”. Sin embargo, el cierre de un Scanner conectado a System.in requiere un manejo cuidadoso para evitar problemas inesperados. En este tutorial, aprenderemos por qué es importante cerrar un Scanner y cómo hacerlo en Java.
2. Entendiendo la Advertencia
En Java, debemos cerrar recursos como archivos, conexiones de red y flujos de entrada después de su uso para liberar memoria del sistema. La clase Scanner lee entradas, como valores primitivos y cadenas, de diversas fuentes, incluidos archivos y System.in. Dado que implementa la interfaz Closeable, retiene recursos que deben liberarse cuando ya no son necesarios.
Algunos IDEs, como Eclipse y Visual Studio Code, muestran advertencias si no cerramos adecuadamente un objeto Scanner. Por ejemplo, si no cerramos explícitamente un objeto Scanner, el IDE muestra la advertencia de fuga de recursos.
3. Cerrando un Scanner Con el Método close()
En Java, podemos cerrar un Scanner utilizando el método close(), lo que ayuda a liberar recursos del sistema. Esto es especialmente importante al leer de un archivo o de System.in.
Es recomendable cerrar un Scanner en el bloque finally para asegurar una correcta clausura incluso si ocurre una excepción. Esto ayuda a prevenir fugas de recursos:
@Test
void givenUserName_whenGetGreetingMessage_thenReturnsWelcomeMessage() {
String input = "Anees\n";
ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes());
Scanner scanner = new Scanner(inputStream);
ScannerClose example = new ScannerClose();
String result = example.getGreetingMessage(scanner);
assertEquals("Hi, Anees Welcome to Baeldung", result);
scanner.close();
}
Cerrar recursos es una buena práctica. Sin embargo, cerrar un Scanner que esté vinculado a System.in puede generar problemas. System.in representa el flujo de entrada estándar, normalmente el teclado. Si cerramos este flujo, el programa ya no podrá leer la entrada del usuario, y no podemos reabrir System.in dentro de la misma ejecución del programa.
Además, si creamos múltiples instancias de Scanner para System.in, cerrar cualquiera de ellas cerrará el flujo de entrada para todo el programa. Como resultado, podríamos encontrar excepciones al intentar leer la entrada nuevamente:
Scanner scanner = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.println("Hi, " + name + " Welcome to Baeldung!");
scanner.close();
System.out.print("Enter your age: ");
int age = scanner.nextInt();
System.out.println("Your age is: " + age);
Aquí, intentamos leer age, pero el Scanner fue cerrado anteriormente. Como resultado, encontramos la excepción IllegalStateException: Scanner closed:
Enter your name: Anees
Hi, Anees Welcome to Baeldung!
Enter your age: Exception in thread "main" java.lang.IllegalStateException: Scanner closed
Para evitar problemas con Scanner, deberíamos utilizar una única instancia para System.in y evitar cerrarla o cerrarla solo cuando ya no necesitemos más entrada.
4. Cerrando un Scanner Usando try-with-resources
Podemos utilizar try-with-resources para cerrar automáticamente el Scanner al final del bloque, incluso si ocurre una excepción. Este enfoque elimina la necesidad de un bloque finally y cierra automáticamente los recursos, lo que reduce el riesgo de fugas de recursos:
@Test
void givenUserName_whenGetGreetingMessage_thenReturnsWelcomeMessage() {
String input = "Anees\n";
ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes());
String result;
try (Scanner scanner = new Scanner(inputStream)) {
ScannerTryWithResources example = new ScannerTryWithResources();
result = example.getGreetingMessage(scanner);
}
assertEquals("Hi, Anees Welcome to Baeldung", result);
}
Cuando el bloque try termina su ejecución, Java cierra automáticamente la instancia de Scanner, haciendo el código más limpio y confiable. Por lo tanto, el uso de try-with-resources es recomendado ya que asegura una correcta limpieza al cerrar un Scanner.
5. Conclusión
En este artículo, aprendimos por qué es importante cerrar un Scanner y cómo hacerlo correctamente. Una adecuada gestión de recursos ayuda a prevenir fugas y asegura una ejecución suave del programa.
Si bien es necesario cerrar un Scanner al leer de archivos, manejar System.in requiere precauciones adicionales. Utilizar una única instancia de Scanner y cerrarla solo cuando ya no necesitemos más entrada ayuda a evitar problemas.
El enfoque de try-with-resources simplifica la gestión de recursos al garantizar cierre automático, haciendo que el código sea más limpio y confiable.