0

Please check the else condition's sc.nextLine(), here I am giving 10 numbers and then getting their sum. If provides any invalid data(which is not int), it will go to else condition. consider input as - 1 2 3 d Then it shows the invalid data line twice. if I put sc.nextLine() outside from the else, it works fine. I want to know the logic behind two times printing.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        int count = 0;
        int sum = 0;
        Scanner sc = new Scanner(System.in);


        while (true) {

            System.out.print("Enter number " + (count + 1) + " - ");
            boolean isInt = sc.hasNextInt();
            if (isInt) {
                int num = sc.nextInt();
                sum += num;
                count++;
                if (count == 10) {
                    break;
                }
            } else {
                System.out.print("Invalid number, put int");

                sc.nextLine();

            }

            //  sc.nextLine();
        }

        System.out.println(sum);
        sc.close();
    }

}
sunny
  • 29
  • 4
  • why aren't you just using nextInt? – Stultuske Apr 20 '20 at 08:58
  • You also get an exception. You need to check if you reached the end of the stream or I would simply add an `break` to the else-part to end the loop if invalid data were found – Ackdari Apr 20 '20 at 09:03
  • 1
    You are not getting rid of the old invalid input so it will be still available to read for you sc.nextLine() even user enters the input here. just consume it before you proceed with the fallback. more over you have not exited the loop. – sarath kumar Apr 20 '20 at 09:13
  • Related: https://stackoverflow.com/questions/13102045/scanner-is-skipping-nextline-after-using-next-or-nextfoo – Sweeper Apr 20 '20 at 09:17
  • @Ackdari- exception? what kind of exception? In case of invalid input, count won't increase and till the time user gives the input in int, it will keep on asking the input. – sunny Apr 20 '20 at 09:52

1 Answers1

1

There are three things that make up this issue:

  • nextInt only consumes the characters that make up the next integer, and goes no further than that.
  • nextLine keeps consuming characters until it reaches the next new line character. It also consumes the new line character
  • hasNextInt treats new lines as delimiters by default.

Let's say the code has ran to the line boolean isInt = sc.hasNextInt(); and you entered d and pressed enter (i.e. 4th iteration of the loop). At this point the internal state of the scanner can be visualised like so:

3 \n d \n
 ^

\n denotes new line characters and ^ denotes where the scanner is currently scanning. The last call to nextInt consumed the 3, but not the new line after it, which causes the scanner to be where it is at right now.

Now, the next token, d, is scanned (but not consumed!). It is not an int, so hasNextInt returns false. Your else block gets executed. The error message is printed. nextLine consumes everything until the next new line character, including the new line character, which moves the pointer to:

3 \n d \n
    ^

Now we are at the next iteration of the loop, the next token is still d, so the same thing happens again. Your else block, runs, error message prints, nextLine consumes, and the pointer is moved:

3 \n d \n
         ^

Compare this to the case where the nextLine is outside the else. This means that every time hasNextInt is called, the pointer will always be after a \n. The pointer will always be moved to after a \n by the nextLine from the previous iteration of the loop. In other words, each iteration of the loop, you always consume the new line after the number.

Sweeper
  • 145,870
  • 17
  • 129
  • 225