Search code examples
javajava.util.scannerinputstreamsystem.in

How can the hasNext methods of Scanner "not advance past any input"?


In the hasNext and hasNextXxx methods of java.util.Scanner it reads:

Returns true if this scanner has another token in its input. This method may block while waiting for input to scan. The scanner does not advance past any input.

How can the scanner not advance through the input stream while it clearly has to check if a next token is present in the input (as Readable or InputStream)?


Solution

  • There are two notions of "advancing through input" being conflated here.

    The first notion is reading more bytes from the InputStream, which of course the Scanner has to do in order to test whether it has a next token. The Scanner does this by buffering the new bytes read from the InputStream, so that those bytes can later be read from the Scanner when necessary. We could call this "advancing through the input stream".

    The second notion is advancing the position of the next byte to be consumed from the buffer. This happens when you call methods like next which consume tokens, to mark that those bytes have been "used" and shouldn't be read again; calling next advances the position in the buffer. We could call this "advancing through the input in the Scanner's buffer".

    The documentation's statement "The scanner does not advance past any input" is the second notion; calling hasNext doesn't advance through the Scanner's buffer, it merely reads more bytes from the input stream into the buffer. To verify this, you can try creating an input stream, calling hasNext, and then reading the next character (rather than the next token) using nextInLine:

    > InputStream is = new ByteArrayInputStream("hello world".getBytes());
    > Scanner sc = new Scanner(is);
    > sc.next()
    "hello" (String)
    > sc.hasNext()
    true (boolean)
    > sc.nextInLine(".")
    " " (String)
    

    So calling hasNext not only doesn't consume the next token, but it also doesn't consume the delimiter before the next token. The Scanner has not "advance[d] past any input" in this sense.