Search code examples
javajava.util.scannerdelimiter

Problem with custom delimiter for Scanner in Java


I want to avoid the issue of "new line character" that is generated by pressing the enter key when I enter a number for nextInt(), since nextLine() will consume the new line character and won't let me input the string.

I am using a custom Delimiter to avoid this issue so that nextInt() can consume the end of line character as well

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
    sc.useDelimiter("\\n");
    System.out.println("Enter your age");
    int age=sc.nextInt();
    System.out.println("Enter your name");
    String name=sc.nextLine();
    System.out.println("Age is "+ age);
    System.out.println("Name is "+ name);
    }
}

However when I run this program I get this error :

Enter your age
4
Exception in thread "main" java.util.InputMismatchException
        at java.base/java.util.Scanner.throwFor(Scanner.java:939)
        at java.base/java.util.Scanner.next(Scanner.java:1594)
        at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
        at java.base/java.util.Scanner.nextInt(Scanner.java:2212)
        at Test.main(Test.java:8)

I can't understand why I am getting an InputMismatchException. Can someone explain how this delimiter works?

As pointed by @Abra in comments, if I use next() instead of nextLine() it works as intended. The question is why does nextLine() doesn't work?


Solution

  • The InputMismatchException was thrown because you used the wrong line separator for your OS. nextInt reads the next token (i.e. stops before the delimiter). Since you have entered 4\r\n, the next token is 4\r, which is not a valid int.

    First, use the correct line separator for your OS. A platform independent way to do this would be:

    sc.useDelimiter(Pattern.quote(System.lineSeparator()));
    

    Now the scanner reads the int correctly, but nextLine still reads an empty string.

    This is because unlike next or nextInt etc, nextLine doesn't care about delimiters. It sees \r\n in front of it, and decides that that is the end of the current line, and returns everything before that.

    nextLine:

    Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line (in this case, there is nothing).

    next: Finds and returns the next complete token from this scanner. A complete token is preceded and followed by input that matches the delimiter pattern.

    See also the prose in the class documentation:

    The next() and hasNext() methods and their companion methods (such as nextInt() and hasNextInt()) first skip any input that matches the delimiter pattern, and then attempt to return the next token.

    After reading the int, the remaining input would be \r\nJohn Doe\r\n, John Doe is preceded and followed by the delimiter - this matches exactly what it means to be a "complete token", so you can read this with next() instead.