Dragon-Ash
Dragon-Ash

Reputation: 71

Java and nextInt() - what if user just hits enter?

I'm using a Scanner object to read in an integer from the user in a try/catch block. I catch wrong inputs (user entered a letter instead of a number etc). But if the user simply hits 'Enter' at the prompt, it simply enters a new line, and waits for the user to hit a key other than "Enter".

I can't see an easy way to capture this and let the user know they need to do something...?

Upvotes: 0

Views: 2289

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

If you want to know when the user enters a blank string (or you don't care and just want to deal with invalid input), I'd start by using Scanner#nextLine instead of Scanner#nextInt or Scanner#hasNextInt

By reading the whole line of text, you will also overcome the issue of the dangling new line character been left in the buffer, which can have adverse effects if you try and read from the Scanner again.

I'd then parse the int through a seperate workflow, for example...

Scanner scanner = new Scanner(System.in);
Integer intValue = null;
do {
    System.out.print("Please enter an int: ");
    String text = scanner.nextLine();
    try {
        intValue = Integer.parseInt(text);
    } catch (NumberFormatException exp) {
        if (text.isEmpty()) {
            System.out.println("You must provide an input");
        } else {
            System.out.println(text + " is not a valid int value");
        }
    }
} while (intValue == null);

System.out.println(">> " + intValue);

System.out.print("This input should not be skipped: ");
String nextLine = scanner.nextLine();
System.out.println(">> " + nextLine);

Personally, I don't like using try-catch as a control mechanism and would instead make use of a second Scanner to do the parsing, but I appreciate that some people don't like that workflow either.

Also, I tried using useDelimiter("\\R");, but this did not solve the problem for me, in fact, it created more.

If I used hasNextInt or nextInt, I could press Enter twice, before it was handled. Subsequent inputs also seemed to double up (it would display two error messages) and didn't solve the issue of a dangling new line been left in the buffer. But, I'm probably no using it as expected.

So I ended up using the above workflow anyway.

I, personally, prefer to get the whole line of text from the user and then parse it as a seperate workflow, this reduces the potential for a lot of other issues associated with getting input from the user when using Scanner (looking at you dangling new lines)

Upvotes: 2

rzwitserloot
rzwitserloot

Reputation: 102852

Simply configure the scanner for keyboard input. You do so as follows:

Scanner s = new Scanner(System.in);
s.useDelimiter("\\R"); // this fixes everything

Then, use any of the .nextX() methods to read whatever you want to read - except nextLine() which you simply do not use. ALL the next methods read entire lines (.nextInt() reads a line and parses it as an int, .next() just reads a line, etcetera).

Why?

Out of the box, scanner is configured to treat 'any amount of whitespace' as the delimiter. This is not what you want or expect when dealing with keyboard input. As a consequence.. just hitting enter a bunch of times doesn't do anything - the delimiter is any amount of whitespace, and enter is.. whitespace. So just repeatedly hitting enter is just more delimiter; nothing happens.

By setting the delimiter to \\R, which is: Exactly one newline of any sort (different platforms have different newlines, \\R works for all of them), multiple enters would mean that the user is entering multiple delimiters, meaning, the .nextX methods return 'the things in between'. Blank string if need be.

This means calling .nextInt() when the user is repeatedly hitting enter, there are tokens being generated that the .next methods will return to you, but it's invalid when you ask .nextInt(). Now there is no difference whatsoever between a user just hitting enter and typing 'hello' and hitting enter. This makes it easy - just catch the appropriate exception (or use .hasNextInt() instead - whichever strategy you prefer). Works for both scenarios now.

Upvotes: 1

Related Questions