I've come across an issue with my scanner functionality. Even after entering "exit" in the terminal, the scanner keeps running. My suspicion is that this behavior is linked to the revertState() function inside of the implementation of hasNext(), but I'm not sure.
String cmd;
do {
cmd = scanner.nextLine();
// ...
}
System.out.printf("%b%n", !cmd.equals("exit"));
} while(scanner.hasNext() && !cmd.equals("exit"));
However, rearranging the statement to !cmd.equals("exit") && scanner.hasNext() works, because scanner.hasNext() will not be invoked, thanks to the short-circuit evaluation.
I would also like to know how the hasNext() function is blocking this whole process.
No, it's down to your misunderstanding of what these things mean.
Scannerwraps a resource - in your case,System.in.System.inis NOT the keyboard. It's 'standard in', and who knows what that is. It might be the keyboard. It might be a file. It might be nothing. Try it:java -cp myClasspath com.foo.MyApp <somefile.txtand nowSystem.inrepresents the contents of that file.The crucial difference between files and keyboard
The concept 'it has ended' doesn't really apply to keyboards. However, it would to files: Once the file you are piping into a process has reached its end, that is it; it has ended forever. It is possible for the code to realize: No data is there. Will ever be there. For the rest of time.
In contrast a keyboard does not end (well, there's CTRL+D/CTRL+Z but let's leave explicitly 'closing the keyboard' out of it, clearly you aren't thinking of this if you ask this question).
You wrote your code assuming that it will; that's where your mistake is.
Your code, after the user types 'exit' and hits enter, asks: "Hey, is there another token?" via
hasNext(). The answer is: Who knows - maybe. Maybe there will be one 5 minutes from now. The question cannot be answered (yet) by the system. You thought, perhaps, thathasNext()will wait a few seconds for the user to act and then draw the conclusion: Eh, nah, the user appears done. Or possibly that it has a crystal ball and attempts to scan the user's brain to find out if the user feels they are done - which, hopefully by putting it that way, should make you realize that's not how it works. Or you are thinking:hasNext()always returns instantly - it returnstrueif the user has already typed something, and false if the user hasn't yet typed something - what is false now could be true later.That's.. just not how that function works. If
hasNext()returnsfalse, that's it. The way that API works, that cannot change - no new token means no new token. Not now. Not next minute. Not next year. Hence, why that method does not return at all - the user might type more.What you want, presumably, is to just check for
!cmd.equals("exit"). The reason 'swapping them around' works is that the&&operator 'short circuits': If evaluating the left hand side gives a definitive answer, the right hand side isn't evaluated at all, so, if!cmd.equals("exit")evaluates tofalse(becausecmdis equal to"exit"),scanner.hasNext()isn't evaluated. That's a good thing, because evaluatingscanner.hasNext()hangs your app.Attempting to detect CTRL+D/CTRL+Z is kinda tricky; generally if you're writing an app designed to be an interactive command line thing, just detect 'exit' - i.e. just remove your
hasNext(), it doesn't do what yo think it does and serves no purpose here.