Introducción
Leer la entrada del usuario es el primer paso para escribir un software Java útil. La entrada del usuario puede tener muchas formas: interacciones con el mouse y el teclado, una solicitud de red, argumentos en la línea de comandos, archivos que se actualizan con datos relevantes para la ejecución de un programa, etc.
Nos centraremos en la entrada del teclado a través de algo llamado el flujo de entrada estándar. Puede reconocerlo como Java System.in
.
Vamos a usar Scanner
clase para facilitar nuestra interacción con la secuencia subyacente. Ya que Scanner
tiene algunas desventajas, también usaremos el BufferedReader
y InputStreamReader
clases para procesar el System.in
arroyo.
Al final, nosotros Decorar las InputStream
clase e implementar nuestra propia costumbre UncloseableInputStream
para manejar problemas con el Scanner
clase.
Clase de escáner Java
El java.util.Scanner
La clase es un escáner simple que puede analizar y manejar entradas primitivas, cadenas y secuencias. Ya que System.in
es solo un InputStream
, podemos construir un Scanner
como tal:
Scanner sc = new Scanner(System.in);
Este Scanner
instancia ahora puede escanear y analizar booleanos, enteros, flotantes, bytes y cadenas.
Veamos cómo podemos extraer información de un Scanner
en variables con las que podemos trabajar:
Scanner sc = new Scanner(System.in); // Read an integer into a variable
int myInteger = sc.nextInt(); // Read a byte into a variable
byte myByte = sc.nextByte(); // Read a line until newline or EOF into a string
String myLine = sc.nextLine(); // Closing the scanner
sc.close();
Nuevamente, el constructor no tiene que tomar System.in
. Puede tomar cualquier File
, InputStream
, Readable
, ReadableByteChannel
, Path
(de un archivo para leer), o incluso String
. Además, como segundo argumento, puede especificar una codificación de caracteres para interpretar dichos caracteres de la siguiente manera:
Scanner sc = new Scanner(new FileInputStream("myFile.txt"), "UTF-8");
Tenga en cuenta que Scanner debe cerrarse cuando termine de trabajar con él. La forma más sencilla de hacerlo es a través del probar con recursos .
Métodos de escáner para leer
Los métodos disponibles para leer el próximo token utilizando el método del escáner son:
Método | Tipo de retorno | Descripción |
siguiente() | Cordón | Encuentra y devuelve el siguiente token completo del escáner. |
nextByte () | byte | Escanea el siguiente token de la entrada como un byte. |
nextDouble () | doble | Escanea el siguiente token de la entrada como un doble. |
nextFloat () | flotar | Escanea el siguiente token de la entrada como flotante. |
nextInt () | int | Escanea el siguiente token de la entrada como int. |
nextLong () | Corto | Escanea el siguiente token de la entrada como largo. |
nextShort () | Corto | Escanea el siguiente token de la entrada como un corto. |
nextBoolean () | booleano | Escanea el siguiente token de la entrada en un valor booleano y devuelve ese valor. |
línea siguiente() | Cordón | Avanza este escáner más allá de la línea actual y devuelve la entrada que se omitió. |
Un método digno de mención es el hasNext()
método: un método genérico que devolverá true
si hay algún tipo de token para leer. Hay métodos específicos de tipo como hasNextInt()
, hasNextFloat()
, hasNextLine()
etc. que puedes usar de la misma manera.
Problemas al utilizar System.in con escáner
Un gran problema con System.in
es que es un InputStream
. Al trabajar con él, el Scanner
siempre esperará más información hasta que InputStream
está cerrado. Una vez que se cierra la transmisión, ya no podemos acceder a la entrada desde Scanner
.
Además de cerrarse, el Scanner
la clase también cerrará el InputStream
si implementa Closeable
.
Como InputStream
hace, eso significa que el Scanner
cerrará el System.in
transmitir a la totalidad de su programa.
Dicho esto, si cierras un Scanner
y por lo tanto la System.in
también, no puedes usar System.in
nuevo:
Scanner sc = new Scanner(System.in);
System.out.println(sc.nextInt());
sc.close();
System.out.println("Closing the scanner..."); sc = new Scanner(System.in);
System.out.println(sc.nextInt());
sc.close();
System.out.println("Closing the scanner...");
Esto resulta en:
1
1
Closing the scanner...
Exception in thread "main" java.util.NoSuchElementException at java.util.Scanner.throwFor(Scanner.java:862) at java.util.Scanner.next(Scanner.java:1485) at java.util.Scanner.nextInt(Scanner.java:2117) at java.util.Scanner.nextInt(Scanner.java:2076) at com.company.Main.main(Main.java:18)
Esto hace que trabajar con Scanner
y System.in
mucho más complicado. Arreglaremos esto en la sección final.
Lector almacenado en búfer y Lector de flujo de entrada
En lugar de un Scanner
, también puedes usar un BufferedReader
a lo largo de un InputStreamReader
para obtener la entrada del usuario:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line; while((line = br.readLine()) != null){ System.out.println(String.format("The input is: %s", line));
}
Aquí, solo repetimos la cadena de entrada con un prefijo:
Hello!
The input is: Hello!
I'd like to order some extra large fries.
The input is: I'd like to order some extra large fries.
^D Process finished with exit code 0
El BufferedReader
es adecuado para leer cadenas, pero no tiene métodos incorporados para manejar números. Para leer un número entero, tendría que analizarlo desde una cadena:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int a = Integer.parseInt(br.readLine());
System.out.println(a);
Esto funciona bien ahora:
5
5
Personalizable no cerrable Flujo de entrada
Afortunadamente, hay una solución para Scanner
cerrando el System.in
transmitir gracias a la Patrón de diseño de decorador. Podemos implementar nuestro propio InputStream
y solo haz el close()
método no hacer nada para que cuando Scanner
lo llama, no afectará la entrada estándar subyacente:
public class UnclosableInputStreamDecorator extends InputStream { private final InputStream inputStream; public UnclosableInputStreamDecorator(InputStream inputStream) { this.inputStream = inputStream; } @Override public int read() throws IOException { return inputStream.read(); } @Override public int read(byte[] b) throws IOException { return inputStream.read(b); } @Override public int read(byte[] b, int off, int len) throws IOException { return inputStream.read(b, off, len); } @Override public long skip(long n) throws IOException { return inputStream.skip(n); } @Override public int available() throws IOException { return inputStream.available(); } @Override public synchronized void mark(int readlimit) { inputStream.mark(readlimit); } @Override public synchronized void reset() throws IOException { inputStream.reset(); } @Override public boolean markSupported() { return inputStream.markSupported(); } @Override public void close() throws IOException { // Do nothing }
}
Cuando modificamos nuestro código problemático para usar el personalizado InputStream
, se ejecutará sin problemas:
public class ScannerDemo { public static void main(String[] args) { Scanner sc = new Scanner(new UnclosableInputStreamDecorator(System.in)); System.out.println(sc.nextInt()); sc.close(); System.out.println("Closing the scanner..."); sc = new Scanner(new UnclosableInputStreamDecorator(System.in)); System.out.println(sc.nextInt()); sc.close(); System.out.println("Closing the scanner..."); }
}
Ejecutar esto dará como resultado:
1
1
Closing the scanner...
1
1
Closing the scanner...
Conclusión
En este artículo, hemos cubierto cómo usar el Scanner
class para leer la entrada del usuario. Luego usamos el BufferedReader
clase junto a la InputStreamReader
como un enfoque alternativo
Finalmente, hemos implementado nuestro propio InputStream
para evitar el problema de Scanner
cerrando el System.in
transmisión para todo el programa.
Con suerte, ha aprendido a manejar la entrada de la consola básica en Java y algunos errores comunes que puede encontrar en el camino.
Fuente: https://stackabuse.com/how-to-get-user-input-in-java/