java java.util.scanner

java - ¿Por qué hasNext() False, pero hasNextLine() es True?



java.util.scanner (5)

Pregunta

¿Cómo es que para un objeto de escáner el método hasNextLine() devuelve verdadero mientras que el método hasNext() devuelve falso?

Nota: Según el archivo de entrada, el método hasNext() devuelve el resultado como se esperaba; hasNextLine() no devuelve el resultado correcto.

Código

Aquí está el código que estoy ejecutando que está creando los resultados a continuación:

public void ScannerTest(Reader fileReaderObject){ Scanner scannerObj = new Scanner(fileReaderObject); for(int i = 1; scannerObj.hasNext(); i++){ System.out.println(i + ": " + scannerObj.next()); System.out.println("Has next line: " + scannerObj.hasNextLine()); System.out.println("Has next: " + scannerObj.hasNext()); } System.out.println(); scannerObj.close(); }

Fichero de entrada

El siguiente es el contenido real del archivo que estoy pasando a este escáner:

a 3 9 b 3 6 c 3 3 d 2 8 e 2 5 f 2 2 g 1 7 h 1 4 i 1 1

Resultado

El siguiente es el final de lo que se imprime en la consola cuando ejecuto mi código, e incluye la parte que no puedo entender:

25: i Has next line: true Has next: true 26: 1 Has next line: true Has next: true 27: 1 Has next line: true Has next: false


Respuesta corta

Tiene una línea vacía al final del archivo.

Motivo de la línea vacía.

Si toma su contenido y lo guarda, por ejemplo, en un archivo txt, algunos editores agregarán una nueva línea vacía a su archivo.

Los editores se comportan de esta manera, porque esto es parte del estándar POSIX :

Línea 3.206

Una secuencia de cero o más no caracteres más un carácter de terminación.

Este tema ha sido discutido en este hilo .

Documentación de Java Scanner

Aquí está la documentación de la clase Java 8 Scanner .

hasNext()

Devuelve verdadero si este escáner tiene otro token en su entrada.

hasNextLine()

Devuelve verdadero si hay otra línea en la entrada de este escáner.

Motivo del comportamiento del código Java

Debido a los hechos descritos anteriormente, hasNextLine() devolverá true , pero hasNext() no puede encontrar nada, lo que puede reconocer como Token y, por lo tanto, devuelve false .

Para obtener información adicional, consulte la publicación durron597 .


Tiene una nueva línea adicional al final de su archivo.

  • hasNextLine() comprueba si hay otro linePattern en el búfer.
  • hasNext() comprueba si hay un token analizable en el búfer, separado por el delimitador del escáner.

Dado que el delimitador del escáner es un espacio en blanco y el linePattern también es un espacio en blanco, es posible que haya un linePattern en el búfer pero no tokens analizables.

Por lo general, la forma más común de lidiar con este problema siempre llama a nextLine() después de analizar todos los tokens (por ejemplo, números) en cada línea de su texto. Debe hacer esto cuando use Scanner cuando lea la entrada de un usuario también de System.in . Para avanzar el escáner más allá de este delimitador de espacios en blanco, debe usar scanner.nextLine() para borrar el delimitador de línea. Consulte: Uso de scanner.nextLine ()

Apéndice:

LinePattern se define como un Pattern que coincide con esto:

private static final String LINE_SEPARATOR_PATTERN = "/r/n|[/n/r/u2028/u2029/u0085]"; private static final String LINE_PATTERN = ".*("+LINE_SEPARATOR_PATTERN+")|.+$";

El delimitador de token predeterminado es este Pattern :

private static Pattern WHITESPACE_PATTERN = Pattern.compile( "//p{javaWhitespace}+");


El concepto básico de hasNext () y hasNextLine () es

hasNextLine : - Devuelve verdadero si hay otra línea en la entrada de este escáner. Este método puede bloquearse mientras espera la entrada. El escáner no avanza más allá de ninguna entrada.

Devuelve: verdadero si y solo si este escáner tiene otra línea de entrada. Lanza: IllegalStateException - si este escáner está cerrado

hasNext

Devuelve verdadero si el siguiente token completo coincide con el patrón especificado.

Un token completo tiene el prefijo y el postfijo por entrada que coincida con el patrón delimitador. Este método puede bloquearse mientras espera la entrada. El escáner no avanza más allá de ninguna entrada.

Parámetros: patrón: el patrón para buscar

Devuelve: verdadero si y solo si este escáner tiene otra ficha que coincida con el patrón especificado

Desde su última entrada diciendo verdadero para nextLine () porque Una llamada a scan.nextLine (); devuelve el siguiente token. Es importante tener en cuenta que el escáner devuelve un espacio y una letra, porque está leyendo desde el final del último token hasta el comienzo de la siguiente línea.


Está consumiendo el valor de next() , pero solicita hasNext() y hasNextLine() . next() , por defecto, devuelve todo al siguiente whitespace() . Entonces, está iterando a través de todas las cadenas separadas por espacios en blanco, y después de cada una de ellas está preguntando sobre nextLine() .

i 1 1 -> hasNextLine() ? Cierto. hasNext() ? También es cierto

1 1 -> hasNextLine() ? Cierto. hasNext() ? También es cierto (todavía queda un espacio en blanco)

1 -> hasNextLine() ? Verdadero (separador de línea, probablemente). haxNext? Falso, ya no hay espacios en blanco.


La razón es que hasNext() comprueba si hay más caracteres disponibles que no sean espacios en blanco. hasNextLine() comprueba si hay otra línea de texto disponible. Su archivo de texto probablemente tenga una nueva línea al final, por lo que tiene otra línea pero no más caracteres que no sean espacios en blanco.

Muchos editores de texto agregan automáticamente una nueva línea al final de un archivo si aún no hay una.

En otras palabras, su archivo de entrada no es este (los números son números de línea):

1. a 3 9 2. b 3 6 3. c 3 3 4. d 2 8 5. e 2 5

En realidad es esto:

1. a 3 9 2. b 3 6 3. c 3 3 4. d 2 8 5. e 2 5 6.