Esto nos pasa a todos y el problema se debe a como funciona la clase Scanner.
A ver si logro explicarlo fácilmente.
Cuando tu introduces una palabra, por ejemplo:
- hola
Tu lo que haces es pulsar las teclas "h", "o", "l", "a" y luego pulsar enter/intro para introducirlo.
Entonces, en realidad al Scanner no le llegan solo los caracteres "hola", le llega también el caracter "\r" o también llamado "retorno de carro" que es que representa el haber pulsado la tecla enter/intro.
Es un caracter especial, no se representa en pantalla, pero tiene su función, que es indicar donde termina la linea de texto introducida.
Todos estos caracteres los guarda el Scanner en un
stream o flujo de datos, a espera de que le digamos que hacer con él.
Así que el Scanner ahora tendría:
- hola\r
Si le ordenamos al Scanner, que nos lea la siguiente linea -->
nextLine()
Cogerá todos los caracteres, incluido el "\r", y los transformará en un String para que ya luego hagamos con el lo que necesitemos.
Tras esta operacion, el stream de datos se queda totalmente vacío:
-
Hasta que volvamos a teclar algo.
Creo que esto se entiende fácilmente, ¿no?
Bien, las complicaciones surgen cuando al Scanner le pedimos datos que no son String.
Si pedimos un número y el usuario teclea un "5", en el stream del Scanner ahora tendremos:
-5\r
Entonces, si le decimos al Scanner que de eso que ha recibido nos de un entero-->
nextInt().
Lo que hace es coger solo el caracter "5" y lo transforma en un int.
Pero el caracter especial "\r" no lo coge, ya que esto no puede transformarse en un valor numérico, así que tras proporcionarnos el "5" convertido en un int, el stream del Scanner ¡¡no ha quedado vacío!!, el caracter de retorno de carro sigue estando ahí.
-\r
Si tras esto, seguimos pidiendo datos numéricos, ya sean int, double, float, byte....no habrá ningún problema. El Scanner cogerá los numeros sin ninguna complicación, pero siempre quedará un caracter "\r" en el flujo de datos del Scanner.
El problema viene cuando, tras leer datos numéricos, queremos volver a leer un String usando el
nextLine()
En teoría el
nextLine() debería esperar a que el usuario teclee lo que quiera introducir. Pero, ¿que ocurre?
Lo que ocurre es que el
nextLine() se encuentra que en el flujo de datos del Scanner ya hay un caracter de retorno de carro, un "\r"
Entonces, el
nextLine() piensa erróneamente que el usuario ya ha pulsado la tecla intro/enter. Así que recoge el caracter "\r", forma un String con el (que en la práctica, será un String vacío) y da por finalizado la inserción de datos, sin que el usuario haya tenido la oportunidad de teclear nada.
Esto es lo que te está ocurriendo. Por eso no te da oportunidad de teclear el nombre y solo te deja introducir la calle.
No se si ha quedado claro con esta explicación.
En resumidas cuentas:
- siempre que hayamos leidos datos numéricos, el próximo intento de leer un String con
nextLine() no funcionará, porque al Scanner se le ha quedado almacenado un caracter de "retorno de carro" que es el equivalente a pulsar enter/inbtro, y por lo tanto pensará que el usuario ha pulsado dicha tecla.
Vale, todo esto tan "complejo" es la explicación. Pero, ¿cuál es la solución?
Afortunadamente, es increiblemente sencilla.
Basta con que, tras haber terminado de leer datos numéricos, antes de intentar leer un String, hagamos una llamada extra al metodo
nextLine() para que recoga el caracter "\r".
No hace falta que haga nada con él, no hace falta meterlo en ninguna variable ni nada. Tan solo le llamamos para que "limpie" el flujo de datos del Scanner y ahora ya sí podemos proceder a pedir datos String al usuario.
Resumiendo, basta con que modifiques el código de este modo:
Ya verás que tras esto, si funciona correctamente.
Esta "chapucilla" hay que hacerla siempre que queramos pedir String al usuario tras haber pedido datos de tipo numérico