Autor Tema: Problema clase #Scanner Java nextInt(), nextDouble(), nextFloat() no funcionan  (Leído 3399 veces)

lcanciani

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 5
    • Ver Perfil
Hola, estoy resolviendo ejercicios de arrays del curso Java avanzado de aprenderaprogramar.com y tengo un problema con Scanner.

No me doy cuenta porque no se guarda el primer dato ingresado en la posicion cero del array: nombreAlumnos. ¿Pueden ayudarme?

Enunciado:
Crea un programa en el que se pida por consola el nombre de 2 alumnos y la nota de cada uno de ellos como valor numérico. El resultado que debe mostrarse es el nombre de cada alumno, su nota y su calificacion como texto (Sobresaliente, Notable, Bien o Suspenso).
Para ello crea un array numérico y otro de String (ambos unidimensionales). En el array numérico se insertarán las calificaciones facilitadas por el usuario entre 0 y 10 (debemos controlar que inserte una nota valida), pudiendo ser decimal. En el array de Strings se insertarán los nombres de los alumnos. Crea también un array de String donde insertaremos el resultado de la nota con palabras admitiéndose estos valores: Sobresaliente, Notable, Bien o Suspenso.
El programa debe comprobar la nota de cada alumno teniendo en cuenta esta equivalencia:
Si la nota está entre 0 y 4,99 será un Suspenso.
Si la nota está entre 5 y 6,99 será un Bien.
Si la nota está entre 7 y 8,99 será un Notable.
Si la nota está entre 9 y 10 será un Sobresaliente.
Muestra por pantalla, el alumno su nota y su resultado en palabras utilizando bucles.
Crea los métodos que creas convenientes. Puedes comprobar si tu código es correcto consultando en los foros aprenderaprogramar.com

Código
Código: [Seleccionar]
package arrays2;
import java.util.Scanner;
public class Arrays2 {

    public static void main(String[] args) {
        String alumno;
        double calificacion;
        int cantidadDeAlumnos;
        Scanner en=new Scanner(System.in);
       System.out.println("Ingrese la cantidad de alumnos");
       cantidadDeAlumnos=en.nextInt();
       String []capacidadDeAlumno=new String[4];
       String [] nombreAlumnos=new String[cantidadDeAlumnos];
       double [] arregloCalificaciones=new double [cantidadDeAlumnos];
       System.out.println("Ingrese el nombre de los alumnos: ");
       for(int i=0;i<=nombreAlumnos.length-1;i++){
       
           alumno=en.nextLine();
           nombreAlumnos[i]=alumno;
           
       }
       for(int i=0;i<=nombreAlumnos.length-1;i++){
           System.out.println("Ingrese la calificación de: "+nombreAlumnos[i]);
       calificacion=en.nextInt();
       while (calificacion>10){
       System.out.println("Ingeso una nota incorrecta, ingrese nuevamente");
       calificacion=en.nextInt();
       }
       arregloCalificaciones[i]=calificacion;
       
       }
      capacidadDeAlumno[0]="Suspenso";
      capacidadDeAlumno[1]="Bien";
      capacidadDeAlumno[2]="Notable";
      capacidadDeAlumno[3]="Sobresaliente";
      for(int i=0;i<=1;i++){
          if (arregloCalificaciones[i]<5){
              System.out.println("Alumno: "+nombreAlumnos[i]+
                      " Calificación: "+arregloCalificaciones[i]+" Resultado: "
              +capacidadDeAlumno[0]);
          }
          else if(arregloCalificaciones[i]>=5&&arregloCalificaciones[i]<7){
             System.out.println("Alumno: "+nombreAlumnos[i]+
                      " Calificación: "+arregloCalificaciones[i]+" Resultado: "
              +capacidadDeAlumno[1]);
          }
          else if (arregloCalificaciones[i]>=7&&arregloCalificaciones[i]<9){
             System.out.println("Alumno: "+nombreAlumnos[i]+
                      " Calificación: "+arregloCalificaciones[i]+" Resultado: "
              +capacidadDeAlumno[2]);
          }
          else{
              System.out.println("Alumno: "+nombreAlumnos[i]+
                      " Calificación: "+arregloCalificaciones[i]+" Resultado: "
              +capacidadDeAlumno[3]);
          }
      }
    }
   
}

Salida:
Ingrese la cantidad de alumnos
2
Ingrese el nombre de los alumnos:
jose
Ingrese la calificación de:
8
Ingrese la calificación de: jose
9
Alumno:  Calificación: 8.0 Resultado: Notable
Alumno: jose Calificación: 9.0 Resultado: Sobresaliente
« Última modificación: 17 de Abril 2020, 14:14 por Alex Rodríguez »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re:Ejercicio Arrays
« Respuesta #1 en: 07 de Febrero 2019, 01:04 »
Hola.
El problema se debe a una peculiaridad que tiene la clase Scanner y que hace que siempre que en un mismo programa queramos leer datos numéricos como un int y texto en un String, tendremos problemas seguro....

El problema se debe a que los métodos de la clase Scanner que usamos para recoger datos numéricos: nextInt(), nextDouble(), nextFloat(), etc... solo recogen la parte numérica de lo que hemos tecleado.
Es decir, si yo tecleo el número 52 y pulso enter, en realidad lo que he introducido es:
52\r
Ese último carácter, el \r lo genera la tecla enter, es el símbolo llamado "retorno de carro" y, en este caso, sirve para decirle al objeto Scanner que ya hemos terminado de teclear.

Pues bién, si eso se lo pasamos al método nextLine(), lo cogerá COMPLETO y generará un String. Coge también el \r, aunque no lo vemos porque es "invisible".
En fín, en este caso no hay problema.

Pero si esa entrada se la pasamos a por ejemplo el método nextInt(), este método no cogerá el \r porque no es un valor numérico, SOLO cogerá el 52 y generará un int.

Pero el \r que nextInt() ha ignorado, no desaparece, se queda en el "stream" de entrada de datos por teclado, tal que así:
\r

¿Qué pasa entonces? Pues que si tras leer un valor con nextInt(), luego queremos leer otro con un nextLine().... el nextLine() se va a encontrar con que hay un \r en el "stream" de entrada.
Y erróneamente va a pensar que es que el usuario ya ha pulsado enter, por lo tanto dará por finalizada la entrada de datos y generará un String vacío.... cuando en realidad el usuario no ha tenido la posibilidad de teclear nada.

Esto es lo que te está pasando a tí. Tu primero lees un entero para preguntar cuantos usuarios se van a introducir:
Código: [Seleccionar]
System.out.println("Ingrese la cantidad de alumnos");
cantidadDeAlumnos=en.nextInt();

Esto te deja un \r abandonado en el stream de entrada, por lo tanto, tu primer intento de leer un String, va a fracasar:
Código: [Seleccionar]
System.out.println("Ingrese el nombre de los alumnos: ");
       for(int i=0;i<=nombreAlumnos.length-1;i++){
       
           alumno=en.nextLine();
           nombreAlumnos[i]=alumno;
           
       }
Solo fallará el primero, el resto irán bien porque los nextLine() no dejan \r abandonados...

En fin, vamos a lo importante, ¿cómo solucionar esto?

Por suerte es fácil, de hecho, hay dos formas.

Una, la más sencilla, pero muy poco elegante. Es invocar un nextLine() justo después de haber leido el dato int.
Este nextLine() no se asigna a ninguna variable, simplemente "limpiará" el stream de entrada de cualquier \r que pueda haber.
Como digo, es fácil, pero no es elegante, porque queda un poco raro ir poniendo nextLine() sin asignar en distintas partes del código.
Aunque se puede usar un comentario para aclarar el motivo:
Código: [Seleccionar]
System.out.println("Ingrese la cantidad de alumnos");
cantidadDeAlumnos=en.nextInt();
en.nextLine(); //Para limpiar stream de entrada y poder leer datos String a continuacion


La segunda opción, es solo un poquito más complicada, pero es más elegante y de hecho es la más recomendable por dos motivos que indicaré después.
Consiste en usar SIEMPRE nextLine() para leer datos, tanto si queremos un String como si queremos un dato numérico.
La diferencia es que si queremos un dato numérico, tendremos que "parsearlo" (convertirlo) segun nuestra necesidad.

En este caso, lo haríamos así:
Código: [Seleccionar]
System.out.println("Ingrese la cantidad de alumnos");
cantidadDeAlumnos=Integer.parseInt(en.nextLine());

O si quisieramos leer un dato numérico con decimales:
Código: [Seleccionar]
System.out.println("Ingrese el area del rectángulo: ");
double areaRectan=Double.parseDouble(en.nextLine());

¿Por qué es la opción más recomendable?
  • Como ya hemos dicho, es más elegante. No hay que aclarar nada con comentarios, es evidente con solo leer el código que estamos recogiendo un valor int, o double, o byte o lo que sea...a pesar de que usamos un nextLine()

  • Cuando avances más en tu aprendizaje en Java y comiences a crear ventanitas, botones, formularios con campos de texto, etc... estos formularios SIEMPRE nos van a devolver los valores introducidos por el usuario como String, y SIEMPRE tendremos que "parsearlos" si deseamos un dato numérico.
    Así que mejor ir cogiendo ya la costumbre de este proceso.

  • Otros lenguajes como C#, lenguaje muy similar a Java y que seguramente algún dia querrás/tendrás que meterle mano, realiza la lectura de datos de este mismo modo: pidiendo un String al usuario para luego "parsearlo".
    Así que de nuevo resultará muy útil estar acostumbrado a esta mecánica.
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

lcanciani

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 5
    • Ver Perfil
Re:Ejercicio Arrays
« Respuesta #2 en: 11 de Febrero 2019, 20:36 »
Excelente respuesta, todo entendido. Lo probé en el programita y funciona a la perfección.
Voy a poner en practica los consejos.
Muchas muchas gracias :) :)

 

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".