Autor Tema: JAVA: Limpiar buffer de entrada Scanner leer Strings después de leer números  (Leído 47441 veces)

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 702
    • Ver Perfil
Hola gente, es ya consábido el problema de los objetos Scanner para leer Strings tras haber leido números previamente.

Supuestamente se puede solucionar "limpiando" el buffer haciendo una llamada al método nextLine() sin asignarlo a ninguna variable.

Pero tengo aquí un caso, donde quiero leer un char tras leer números y nada, no hay manera.

Abajo os adjunto el código completo, por si alguien quiere compilarlo sin tener que cambiar nada.

Tiene muchas líneas porque hay varios métodos, pero tan solo hay que fijarse en la línea 39.

Ahí es donde leo un char para evaluar si finalizamos o no el bucle, pero al llegar ahí, peta el programa.

En la línea anterior intento lo de limpiar el buffer, pero no parece tener ningún efecto.

¿Alguna idea?


Código: [Seleccionar]
package estructura_modular;

import java.util.Scanner;

public class Ej12 {

public static void main(String[] args) {
Scanner teclado = new Scanner(System.in);
char opcion;
char salir = 'n';

do
{
System.out.println("\nCONVERSOR DE TEMPERATURAS");
System.out.println("-------------------------\n");
System.out.println("Indique tipo de magnitud que va a introducir.");
System.out.println("Opciones: (c)Celsius // (f)Farenheit // (k)Kelvin");
System.out.print("Su opcion(c/f/k): ");
opcion = teclado.next().toLowerCase().charAt(0);

switch(opcion)
{
case 'c':
menuCelsius();
break;
case 'f':
menuFarenheit();
break;
case 'k':
menuKelvin();
break;
default:
System.out.println("No se reconoce magnitud introducida.");
break;
}

System.out.print("¿Desea terminar? (S/N): ");
teclado.nextLine();//Limpiamos buffer de entrada
salir = teclado.next().toLowerCase().charAt(0);
}while (salir != 's');

System.out.println("\n\nFin de programa...");
teclado.close();
}

public static double celAFar(double m)
{
return ( 9 * m / 5) + 32;
}

public static double celAKel(double m)
{
return m + 273.15;
}

public static double farACel(double m)
{
return (m - 32) * 5 / 9;
}

public static double farAKel(double m)
{
return (m - 32) / 1.8 + 273;
}

public static double kelACel(double m)
{
return m - 273.15;
}

public static double kelAFar(double m)
{
return 1.8 * (m - 273) + 32;
}

public static void menuCelsius()
{
Scanner teclado = new Scanner(System.in);
int opcion;
System.out.print("\nIntroduzca la magnitud en Celsius: ");
double magnitud = teclado.nextDouble();

System.out.println("\nConversiones disponibles");
System.out.println("(1) Celsius a Farenheit");
System.out.println("(2) Celsius a Kelvin");
System.out.print("Su opcion (1/2): ");
opcion = teclado.nextInt();

switch(opcion)
{
case 1:
System.out.println(magnitud + "ºC equivalen a " + celAFar(magnitud) + "ºF");
break;
case 2:
System.out.println(magnitud + "ºC equivalen a " + celAKel(magnitud) + "K");
break;
default:
System.out.println("ERROR: No se reconoce opcion seleccionada.");
break;
}
teclado.close();
}

public static void menuFarenheit()
{
Scanner teclado = new Scanner(System.in);
int opcion;
System.out.print("\nIntroduzca la magnitud en Farenheit: ");
double magnitud = teclado.nextDouble();

System.out.println("\nConversiones disponibles");
System.out.println("(1) Farenheit a Celsius");
System.out.println("(2) Farenheit a Kelvin");
System.out.print("Su opcion (1/2): ");
opcion = teclado.nextInt();

switch(opcion)
{
case 1:
System.out.println(magnitud + "ºF equivalen a " + farACel(magnitud) + "ºC");
break;
case 2:
System.out.println(magnitud + "ºF equivalen a " + farAKel(magnitud) + "K");
break;
default:
System.out.println("ERROR: No se reconoce opcion seleccionada.");
break;
}
teclado.close();
}

public static void menuKelvin()
{
Scanner teclado = new Scanner(System.in);
int opcion;
System.out.print("\nIntroduzca la magnitud en Kelvin: ");
double magnitud = teclado.nextDouble();

System.out.println("\nConversiones disponibles");
System.out.println("(1) Kelvin a Celsius");
System.out.println("(2) Kelvin a Farenheit");
System.out.print("Su opcion (1/2): ");
opcion = teclado.nextInt();

switch(opcion)
{
case 1:
System.out.println(magnitud + "K equivalen a " + kelACel(magnitud) + "ºC");
break;
case 2:
System.out.println(magnitud + "K equivalen a " + kelAFar(magnitud) + "ºF");
break;
default:
System.out.println("ERROR: No se reconoce opcion seleccionada.");
break;
}
teclado.close();
}
}
« Última modificación: 21 de Enero 2016, 09:01 por Ogramar »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

pedro,,

  • Moderador Global
  • Experto
  • *******
  • APR2.COM
  • Mensajes: 1292
    • Ver Perfil
Re:JAVA: Limpiar buffer de entrada
« Respuesta #1 en: 18 de Enero 2016, 22:38 »
Hola Kabuto.

He compilado y ejecutado tu código y no me da ningún error.


Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 702
    • Ver Perfil
Re:JAVA: Limpiar buffer de entrada
« Respuesta #2 en: 18 de Enero 2016, 23:50 »
Hola Kabuto.

He compilado y ejecutado tu código y no me da ningún error.

Hola.
Gracias por tu interés.

¿Has podido ejecutar el programa completo?

El error lo da (al menos a mí) cuando antes de salir del bucle principal pregunta si quiero salir o no.
Si por ejemplo al principio, cuando da a elegir entre tres opciones (c/f/k) introduzco una letra distinta de estas, de manera que no muestra ningún menu y  se va directamente al final del bucle para preguntar si quiero salir o repetir. Ahí no hay problema.

En cuanto meto una opción válida, y accedo a los métodos de alguno de los menús donde hay que introducir números, es entonces cuando da error al llegar al momento donde he de recoger el char para decidir si salgo o no.

Esta es la salida que obtengo en la consola:
Citar
CONVERSOR DE TEMPERATURAS
-------------------------

Indique tipo de magnitud que va a introducir.
Opciones: (c)Celsius // (f)Farenheit // (k)Kelvin
Su opcion(c/f/k): f

Introduzca la magnitud en Farenheit: 345

Conversiones disponibles
(1) Farenheit a Celsius
(2) Farenheit a Kelvin
Su opcion (1/2): 2
345.0ºF equivalen a 446.8888888888889K
Exception in thread "main" java.util.NoSuchElementException
   at java.util.Scanner.throwFor(Unknown Source)
   at java.util.Scanner.next(Unknown Source)
   at estructura_modular.Ej12.main(Ej12.java:39)
¿Desea terminar? (S/N):

En situacione similares, lo había solucionado creando un segundo objeto Scanner.
Pero esta vez no me sirve, y lo de limpiar buffer haciendo un NextLine() previo a la pedida de datos, pues tampoco me está sirviendo...
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

pedro,,

  • Moderador Global
  • Experto
  • *******
  • APR2.COM
  • Mensajes: 1292
    • Ver Perfil
Re:JAVA: Limpiar buffer de entrada
« Respuesta #3 en: 19 de Enero 2016, 00:19 »
Si, ejecuté el código sin ningún error.

De todas formas la linea...

Código: [Seleccionar]
teclado.nextLine();//Limpiamos buffer de entrada
no es necesaria, porque el nextInt() que pretendes limpiar del buffer lo usas en otro método, por lo cual cuando el programa sale del método no queda nada en el buffer, a mi me funciona tanto con esa linea como sin ella.

Espero haberme explicado bien.

Saludos.


Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 702
    • Ver Perfil
Re:JAVA: Limpiar buffer de entrada
« Respuesta #4 en: 19 de Enero 2016, 11:28 »
Sí, te entiendo perfectamente. Lo que no entiendo es por qué a tí te funciona y a mi no xD
La línea de limpiar el buffer, la puse porque leí que soluciona este tipo de problemas... pero no me solucionó nada.


¿Puede tener algo que ver el IDE que usemos? En teoría no, se supone que aunque el IDE sea distinto, quien compila y ejecuta es la máquina Java..

Yo uso Eclipse.
Recientemente he querido probar con IntelliJ IDEA, que me han hablado bien... pero no me aclaro con él y aún no he sido capaz ni de ejecutar un programa  :P

No se si probar con NetBeans, a ver si noto algo distinto.
« Última modificación: 21 de Enero 2016, 09:00 por Ogramar »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:JAVA: Limpiar buffer de entrada
« Respuesta #5 en: 19 de Enero 2016, 14:56 »
Código: [Seleccionar]
System.out.print("¿Desea terminar? (S/N): ");
teclado.nextLine();//Limpiamos buffer de entrada
salir = teclado.next().toLowerCase().charAt(0);
}while (salir != 's');
Buenas, no soy un experto, pero mirando tu código creo que teclado.nextLine(); efectivamente "limpia" (es mentira lo que hace es coger la next linea que haya y como no la guarda en ningun sitio, la elimina del Scanner teclado)
Pero como llegado a ese punto, no hay linea alguna , la siguiente que tu escribes 'S/N' es la que descarta y da error Exception in thread "main" java.util.NoSuchElementException que significa no hay siguiente elemento.

Bueno lo que yo haría llegado ese punto, ya que estas reiniciando todo el rato el objeto Scanner teclado. sería ;
Código: [Seleccionar]
System.out.print("¿Desea terminar? (S/N): ");
teclado = new Scanner(System.in);
salir = teclado.next().toLowerCase().charAt(0);
}while (salir != 's');
Esto deberia funcionarte para no tocar mucho más tu código.
Otra forma sería
Código: [Seleccionar]
System.out.print("¿Desea terminar? (S/N): ");
if(teclado != null){ teclado.nextLine();
            //Coge lo que haya si es diferente de null, osea si no esta vacío
                         }
salir = teclado.next().toLowerCase().charAt(0);
}while (salir != 's');


Y eso sí ,menos el static del menu principal, te sobran todos los demas static, las funciones static son otra cosa a lo que tu haces ahí :) son public void NombreDeLaFunción porque no retornan nada, pero el static sobra.
Una funcion es static cuando puedes ejecutarla independientemente de la creacion de un objeto , como ejemplo una formula matematica aplicable en cualquier momento.

Tienes este curso gratuito en la web que es genial NO, lo siguiente;
http://aprenderaprogramar.com/index.php?option=com_content&view=category&id=68&Itemid=188
Saludos.
« Última modificación: 19 de Enero 2016, 15:09 por Lorenzo31 »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 702
    • Ver Perfil
Re:JAVA: Limpiar buffer de entrada
« Respuesta #6 en: 19 de Enero 2016, 22:16 »
Hola Lorenzo31, muchas gracias por tus respuestas.

Si quito lo de static, Eclipse me lanza errores como este cada vez que llamo a alguno de los métodos.
Citar
Cannot make a static reference to the non-static method celAFar(double) from the
type Ej12

He probado lo de reiniciar el objeto Scanner, sin éxito... ya intenté algo parecido antes. Cerrarlo, con .close() y volver a crearlo con new Scanner justo antes de pedir el dato...

Pero nada, no hay manera..


Sin embargo, he encontrado una solución.

Cuando llamos a los métodos que presentan los distintos menús, (los métodos void), les paso el objeto Scanner como parámetro y lo utilizo en esos métodos sin crear/cerrar un nuevo scanner... y así consigo que funcione je je...
No me termina de gustar, pero bueno, peculiaridades del Java con las que hay que lidiar...

Lo raro es que pedro si le funcionase y a mi no. Voy a probar con otro IDE como NetBeans, a ver si percibo alguna diferencia.

Muchas gracias a ambos por vuestra colaboración. Un saludo.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

pedro,,

  • Moderador Global
  • Experto
  • *******
  • APR2.COM
  • Mensajes: 1292
    • Ver Perfil
Re:JAVA: Limpiar buffer de entrada
« Respuesta #7 en: 19 de Enero 2016, 22:53 »
En blueJ no da errores.
Lo probé en netBeans y si me daba errores que te dan a ti, lo solucioné quitando todas las lineas...
Código: [Seleccionar]
teclado.close();que hay en menuCelsius(), menuFarenheit() y menuKelvin()
y también quité la linea ...
Código: [Seleccionar]
eclado.nextLine();//Limpiamos buffer de entradaporque como te dije antes, aquí no tiene ningún sentido.

y Lorenzo tienes toda la razón en el significado de teclado.nextLine(), lo que se quería decir es que se usaba con ese propósito, hacer desaparecer el golpe del intro que no recoge el nextInt().

Saludos.

saludos.

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".