61

Question

How is it that for a scanner object the hasNextLine() method returns true while the hasNext() method returns false?

Note: Based on the input file, the hasNext() method is returning the result as expected; the hasNextLine() does not seem to be returning the correct result.

Code

Here's the code I'm running that's creating the results below:

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();
}

Input File

The following is the actual content of the file that I'm passing to this scanner:

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

Result

The following is the end of what's printed in the console when I run my code, and includes the portion I can't make sense of:

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
John Kugelman
  • 307,513
  • 65
  • 473
  • 519
DRich
  • 933
  • 1
  • 8
  • 23
  • 24
    Is there an empty line at the end of your input file by chance? – Swagin9 Aug 13 '15 at 16:13
  • 15
    `hasNextLine()` returns true if there is a next line, even empty. `hasNext()` returns true if there is one more token. An empty line is a line, which doesn't contain any token. – JB Nizet Aug 13 '15 at 16:15
  • 1
    I think `next` doesn't consume the `\n`, so the "cursor" is right before the newline, thus there is a next line, but there's no more token. – aioobe Aug 13 '15 at 16:15
  • Thanks for the responses. The file does not include a blank line following "i 1 1", so I would expect that once it moves the 2nd "1" on the last line, there is not another line or return character for it to pick up. Interestingly though, if I use the nextLine() method after the loop, I do not get an error. So maybe there is a return character hanging out there? Any thoughts on how I can get the results of the hasNextLine() method and the hasNext() method to align? – DRich Aug 13 '15 at 16:16

5 Answers5

59

You have a single extra newline at the end of your file.

  • hasNextLine() checks to see if there is another linePattern in the buffer.
  • hasNext() checks to see if there is a parseable token in the buffer, as separated by the scanner's delimiter.

Since the scanner's delimiter is whitespace, and the linePattern is also white space, it is possible for there to be a linePattern in the buffer but no parseable tokens.

Typically, the most common way to deal with this issue by always calling nextLine() after parsing all the tokens (e.g. numbers) in each line of your text. You need to do this when using Scanner when reading a user's input too from System.in. To advance the scanner past this whitespace delimiter, you must use scanner.nextLine() to clear the line delimiter. See: Using scanner.nextLine()


Appendix:

LinePattern is defined to be a Pattern that matches this:

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

The default token delimiter is this Pattern:

private static Pattern WHITESPACE_PATTERN = Pattern.compile(
                                            "\\p{javaWhitespace}+");
Community
  • 1
  • 1
durron597
  • 30,764
  • 16
  • 92
  • 150
  • First off, thanks for the detailed response. So I understand that there might be a Line_Separator_Pattern without another token being present. However in the file I can't advance my cursor past the final "1". Is there some whitespace character I can't delete through gedit? – DRich Aug 13 '15 at 16:31
  • `"You have a single extra newline at the end of your file."` - I think it's more general than that, as in - there is any amount of white-space (or whichever delimiter you specified) at the end of the file. – Bernhard Barker Aug 13 '15 at 23:26
  • @Dukeling yes, but OP stated somewhere he checked his file and it didn't have extra white space – durron597 Aug 14 '15 at 00:02
16

The reason is that hasNext() checks if there are any more non-whitespace characters available. hasNextLine() checks to see if there is another line of text available. Your text file probably has a newline at the end of it so it has another line but no more characters that are not whitespace.

Many text editors automatically add a newline to the end of a file if there isn't one already.

In other words, your input file is not this (the numbers are line numbers):

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

It is actually this:

1. a   3   9
2. b   3   6
3. c   3   3
4. d   2   8
5. e   2   5
6. 
Daniel Centore
  • 2,968
  • 1
  • 15
  • 35
14

Short answer

You have an empty line at the end of the file.


Reason for the empty line

If you take your content and save it for example into a txt file, some editors will add an empty new line to your file.

The editors behave this way, because this is part of the POSIX standard:

3.206 Line

A sequence of zero or more non- characters plus a terminating character.

This topic has been discussed in this thread.


Java Scanner documentation

Here is the documentation from the Java 8 Scanner class.

hasNext()

Returns true if this scanner has another token in its input.


hasNextLine()

Returns true if there is another line in the input of this scanner.


Reason for the Java code behavior

Because of the above described facts, hasNextLine() will return true, but hasNext() cannot find anything, which it can recognize as Token and returns therefore false.

For additional infos see durron597 post.

Community
  • 1
  • 1
kamwo
  • 1,794
  • 1
  • 20
  • 28
5

You are consuming the value of next(), but asking for hasNext() and hasNextLine(). next(), per default, returns everything to the next whitespace(). So you are iterating through all whitespace seperated strings, and after each of them you are asking about the nextLine().

i 1 1 -> hasNextLine()? True. hasNext()? Also true.

1 1 -> hasNextLine()? True. hasNext()? Also true (still a whitespace left)

1 -> hasNextLine()? True (Line Seperator, probably). haxNext? False, no whitespace anymore.

Florian Schaetz
  • 9,670
  • 3
  • 27
  • 50
0

The Basic concept of hasNext() and hasNextLine() is

hasNextLine:- Returns true if there is another line in the input of this scanner. This method may block while waiting for input. The scanner does not advance past any input.

Returns: true if and only if this scanner has another line of input Throws: IllegalStateException - if this scanner is closed

hasNext

Returns true if the next complete token matches the specified pattern.

A complete token is prefixed and postfixed by input that matches the delimiter pattern. This method may block while waiting for input. The scanner does not advance past any input.

Parameters: pattern - the pattern to scan for

Returns: true if and only if this scanner has another token matching the specified pattern

Since your last input saying true for nextLine() because A call to scan.nextLine(); returns the next token. It's important to note that the scanner returns a space and a letter, because it's reading from the end of the last token until the beginning of the next line.

Community
  • 1
  • 1