¿Cómo evito que un escáner genere excepciones cuando se ingresa el tipo incorrecto?

Aquí hay un código de muestra:

import java.util.Scanner; class In { public static void main (String[]arg) { Scanner in = new Scanner (System.in) ; System.out.println ("how many are invading?") ; int a = in.nextInt() ; System.out.println (a) ; } } 

Si ejecuto el progtwig y le doy un int como 4 , todo va bien.

Por otro lado, si respondo too many , no se ríe de mi chiste gracioso. En cambio, obtengo esto (como se esperaba):

 Exception in thread "main" java.util.InputMismatchException at java.util.Scanner.throwFor(Scanner.java:819) at java.util.Scanner.next(Scanner.java:1431) at java.util.Scanner.nextInt(Scanner.java:2040) at java.util.Scanner.nextInt(Scanner.java:2000) at In.main(In.java:9) 

¿Hay alguna manera de hacer que ignore las entradas que no están en las entradas o que se le pregunte “¿Cuántos están invadiendo?” Me gustaría saber cómo hacer ambas cosas.

Puede usar uno de los muchos métodos de hasNext* que Scanner tiene para la validación previa.

  if (in.hasNextInt()) { int a = in.nextInt() ; System.out.println(a); } else { System.out.println("Sorry, couldn't understand you!"); } 

Esto evita que incluso se InputMismatchException , porque siempre se asegura de que coincida antes de leerlo.


java.util.Scanner API

  • boolean hasNextInt() : devuelve true si el siguiente token en la entrada de este escáner se puede interpretar como un valor int en la raíz por defecto utilizando el método nextInt() . El escáner no avanza más allá de cualquier entrada.

  • String nextLine() : avanza este escáner más allá de la línea actual y devuelve la entrada que se saltó.

Tenga en cuenta las secciones en negrita. hasNextInt() no avanza más allá de cualquier entrada. Si devuelve true , puede avanzar el escáner llamando a nextInt() , que no lanzará una InputMismatchException .

Si devuelve false , entonces debe pasar la “basura”. La forma más sencilla de hacerlo es simplemente llamando a nextLine() , probablemente dos veces, pero al menos una vez.

Por qué es posible que necesite hacer nextLine() dos veces es lo siguiente: suponga que esta es la entrada ingresada:

 42[enter] too many![enter] 0[enter] 

Digamos que el escáner está al comienzo de esa entrada.

  • hasNextInt() es verdadero, nextInt() devuelve 42 ; el escáner ahora está justo antes del primer [enter] .
  • hasNextInt() es falso, nextLine() devuelve una cadena vacía, un segundo nextLine() devuelve "too many!" ; el escáner ahora está justo después del segundo [enter] .
  • hasNextInt() es verdadero, nextInt() devuelve 0 ; el escáner ahora está justo antes del tercero [enter] .

Aquí hay un ejemplo de poner algunas de estas cosas juntas. Puedes experimentar con él para estudiar cómo funciona Scanner .

  Scanner in = new Scanner (System.in) ; System.out.println("Age?"); while (!in.hasNextInt()) { in.next(); // What happens if you use nextLine() instead? } int age = in.nextInt(); in.nextLine(); // What happens if you remove this statement? System.out.println("Name?"); String name = in.nextLine(); System.out.format("[%s] is %d years old", name, age); 

Digamos que la entrada es:

 He is probably close to 100 now...[enter] Elvis, of course[enter] 

Entonces la última línea del resultado es:

 [Elvis, of course] is 100 years old 

En general, realmente no me gusta usar la misma llamada de biblioteca para leer y analizar. Las bibliotecas de idiomas parecen ser muy inflexibles y, a menudo, no se pueden doblegar a su voluntad.

El primer paso que extrae datos de System.in no debería poder fallar, por lo que debe leerlo como una cadena en una variable, luego convierta esa variable de cadena a una int. Si la conversión falla, genial: imprima su error y continúe.

Cuando envuelves tu transmisión con algo que puede arrojar una excepción, se vuelve un tanto confuso el estado en que todo el lío deja tu flujo.

Siempre es un beneficio que su aplicación arroje un error cuando ocurre un error, en lugar de evitar que ocurra.

Una alternativa es ajustar el código dentro de un bloque try {...} catch {...} para InputMismatchException . Es posible que también desee envolver el código dentro de un ciclo while para que el Scanner continúe solicitándolo hasta que se cumpla una condición específica.