0

I need explanation about how does scanner's hasNextInt() works. In next example:

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    boolean foo = sc.hasNextBoolean();
    System.out.println(sc.nextLine());
}

when program gets to hasNextBoolean(), it waits for my input. Then I press Enter for newline and type true and press Enter again,so the buffer looks like this: [ \n true \n ].
Now the pointer is on word true, and so foo becomes true. But then, the pointer should still be hanging on true, and when next line comes, program should print true, but what happens is that it just prints newline. Why is that case, may I ask?

On the other hand, doing same thing but using nextInt(), works the way that i expected:

    public static void main(String[] args) {
        Scanner skener = new Scanner(System.in);
        try{
        int stagod = skener.nextInt();}
        catch(Exception e){
        System.out.println(skener.nextLine());}

}

Here when program come to skener.nextInt(), I press Enter then type A then press Enter, so the buffer looks like this: [ \n A \n ].
And now, after catching the exception, pointer stays on A and System.out.println(skener.nextLine()); prints A.

  • 2
    Possible duplicate of [Scanner is skipping nextLine() after using next(), nextInt() or other nextFoo() methods](http://stackoverflow.com/questions/13102045/scanner-is-skipping-nextline-after-using-next-nextint-or-other-nextfoo) – Iłya Bursov Apr 11 '17 at 21:53
  • 1
    did you look at the java docs for the method in question? https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html – RAZ_Muh_Taz Apr 11 '17 at 21:54
  • 1
    `sc.hasNextBoolean()` doesn't consume first `\n` which is why first `nextLine()` returns empty line. Try to add another `nextLine` call and you should get `true` (also \n after that will be consumed). – Pshemo Apr 11 '17 at 22:04
  • 1
    In case of `nextInt` first `\n` is consumed correctly (since it is delimiter), because exception is thrown at `A` since it is not int. So here cursor will be placed before that `A` which allows `nextLine` read it. – Pshemo Apr 11 '17 at 22:11
  • @Pshemo So, nextInt() consumes every \n until it comes to something that is not \n, and then it stops (if it's int, it gets consumed also, if it's not, we get an exception). And hasNextBoolean() won't consume anything. Am I right? – aleksaleks123 Apr 11 '17 at 22:53
  • Yes, purpose of `hasSomeType()` is to simply test if next token matches some types. Lets say that we don't know what type of data we will get. We should be able to test same data with `hasNextInt()` or `hasNextBoolean()` safely, so we shouldn't really consume tested token (we have `nextTYPE_NAME()` for that - without `has` prefix). But since there is also `hasNextLine()` which should be affected by first `\n` validating methods shouldn't consume line separator. – Pshemo Apr 11 '17 at 23:03

1 Answers1

0

sc.hasNextBoolean() is working just fine. The problem is that you failed to account for sc.hasNextBoolean() not advancing past the input that it reads.

sc.hasNextBoolean() reads the input but does not advance past it. So after that call, the input buffer would be "\n", one line. sc.nextLine() DOES advance the scanner past the input after reading it. But in this case, it also waits for the user to enter another line. For you, that would be "true\n" which would make the buffer "\ntrue\n" as expected. But the buffer is 2 lines long. sc.nextLine() only reads one line (the next line). That next line is "\n", it's just a line break. After the System.out.println() call. There is still data in the buffer, which is now "true\n". There's still one line left.

You will find that if you add one more System.out.println(sc.nextLine()), your code will work as expected.

The reason why sc.nextInt() works is because it DOES advance the scanner past the input it reads. It waits for a line of input and then reads it. At this point, the buffer is "\n". But then it also advances past that input that it just read, so the buffer is now empty. The next time you call sc.nextLine(), the scanner is at the position before the line you type, rather than a line behind. So you only need one call to sc.nextLine().

The key to your problem is not that the Scanner methods aren't working as expected. Your problem is simply that your failed to consider that one minor, but crucial, detail about the Scanner.hasNextBoolean() method. There's little things in the documentation like that which can make or break a program. Next time, just remember to read the full documentation of the method you are using before you implement it.

Nicholas Greene
  • 125
  • 1
  • 13