ZetCode

Java Scanner

last modified July 18, 2026

In this article we show how to read and parse input in Java using java.util.Scanner.

The Scanner class in Java is a simple text scanner that can parse primitive types and strings using regular expressions. It breaks its input into tokens using a delimiter pattern, which by default matches whitespace.

The Scanner class is commonly used for:

The scanner can read from various input sources including InputStream, File, Path, Readable, and String.

While Scanner is versatile, other classes may be better suited for specific tasks:

Reading user input

The most common use of Scanner is reading user input from the standard input stream (System.in).

Main.java
void main() {

    var scanner = new Scanner(System.in);

    System.out.print("Enter your name: ");
    var name = scanner.nextLine();

    System.out.print("Enter your age: ");
    var age = scanner.nextInt();

    System.out.printf("Hello %s, you are %d years old%n", name, age);
}

The nextLine method reads a line of text, while nextInt reads an integer value. The Scanner automatically handles the conversion from text to the requested type.

$ java Main.java
Enter your name: John
Enter your age: 34
Hello John, you are 34 years old

Reading different data types

The Scanner provides methods for reading various primitive types and common data types. Each method has a corresponding hasNextXxx method for checking availability.

Main.java
void main() {

    var scanner = new Scanner(System.in);

    System.out.print("Enter an integer: ");
    if (scanner.hasNextInt()) {
        var i = scanner.nextInt();
        System.out.printf("Integer: %d%n", i);
    }

    System.out.print("Enter a double: ");
    if (scanner.hasNextDouble()) {
        var d = scanner.nextDouble();
        System.out.printf("Double: %.2f%n", d);
    }

    System.out.print("Enter a boolean: ");
    if (scanner.hasNextBoolean()) {
        var b = scanner.nextBoolean();
        System.out.printf("Boolean: %b%n", b);
    }

    System.out.print("Enter a word: ");
    var token = scanner.next();
    System.out.printf("Token: %s%n", token);
}

The hasNextInt, hasNextDouble, and hasNextBoolean methods check whether the next token can be interpreted as the requested type, preventing InputMismatchException.

$ java Main.java
Enter an integer: 42
Integer: 42
Enter a double: 3.14
Double: 3.14
Enter a boolean: true
Boolean: true
Enter a word: hello
Token: hello

Reading from a file

The Scanner can read input directly from a file, line by line or token by token.

temperatures.txt
Bratislava 25.3
Prague 18.7
Vienna 22.1
Budapest 20.5
Warsaw 16.8
Main.java
void main() throws Exception {

    try (var scanner = new Scanner(new File("temperatures.txt"))) {

        while (scanner.hasNextLine()) {
            var line = scanner.nextLine();
            System.out.println(line);
        }
    }
}

The hasNextLine method checks if there is another line in the input. The try-with-resources statement ensures that the scanner is properly closed after use.

$ java Main.java
Bratislava 25.3
Prague 18.7
Vienna 22.1
Budapest 20.5
Warsaw 16.8

Parsing structured file data

We can combine token-reading methods with line-reading to parse structured data from files.

Main.java
void main() throws Exception {

    try (var scanner = new Scanner(new File("temperatures.txt"))) {

        while (scanner.hasNext()) {

            var city = scanner.next();
            var temperature = scanner.nextDouble();

            System.out.printf("%s: %.1f°C%n", city, temperature);
        }
    }
}

The next method reads the city name as a string token, and nextDouble reads the temperature value. The default whitespace delimiter separates the tokens correctly.

$ java Main.java
Bratislava: 25.3°C
Prague: 18.7°C
Vienna: 22.1°C
Budapest: 20.5°C
Warsaw: 16.8°C

Reading from a string

The Scanner can also parse data directly from a string, which is useful for processing text data embedded in the application.

Main.java
void main() {

    var data = "apple 1.20 banana 0.80 cherry 2.50";

    try (var scanner = new Scanner(data)) {

        while (scanner.hasNext()) {

            var fruit = scanner.next();
            var price = scanner.nextDouble();

            System.out.printf("%s: $%.2f%n", fruit, price);
        }
    }
}

The string is parsed token by token. The Scanner iterates through the text, extracting alternating string and double values.

$ java Main.java
apple: $1.20
banana: $0.80
cherry: $2.50

Custom delimiters

The useDelimiter method sets a custom delimiter pattern for tokenizing the input. This is useful for parsing non-whitespace separated data.

Main.java
void main() {

    var data = "10,20,30,40,50";

    try (var scanner = new Scanner(data)) {

        scanner.useDelimiter(",");

        var sum = 0;

        while (scanner.hasNextInt()) {
            sum += scanner.nextInt();
        }

        System.out.printf("Sum: %d%n", sum);
    }
}

The delimiter is set to a comma with useDelimiter(","), allowing the Scanner to parse comma-separated integer values.

$ java Main.java
Sum: 150

Reading CSV data

A more realistic CSV parsing example demonstrates reading structured tabular data from a file.

employees.csv
John Doe,Software Engineer,75000
Jane Smith,Data Analyst,68000
Robert Brown,DevOps Engineer,82000
Emily Davis,Product Manager,79000
Main.java
void main() throws Exception {

    try (var scanner = new Scanner(new File("employees.csv"))) {

        while (scanner.hasNextLine()) {

            var line = scanner.nextLine();

            try (var lineScanner = new Scanner(line)) {
                lineScanner.useDelimiter(",");

                var name = lineScanner.next();
                var position = lineScanner.next();
                var salary = lineScanner.nextInt();

                System.out.printf("%-20s %-20s $%d%n",
                        name, position, salary);
            }
        }
    }
}

Each line is read with nextLine, then a secondary Scanner parses the comma-separated fields. This nested approach handles CSV data cleanly and is easy to adapt for different formats.

$ java Main.java
John Doe             Software Engineer      $75000
Jane Smith           Data Analyst           $68000
Robert Brown         DevOps Engineer        $82000
Emily Davis          Product Manager        $79000

Finding patterns with findInLine

The findInLine method searches for a pattern in the current line without advancing past the line terminator.

Main.java
void main() {

    var data = """
            Name: John Doe  Age: 34  City: Bratislava
            Name: Jane Doe  Age: 28  City: Prague
            """;

    try (var scanner = new Scanner(data)) {

        while (scanner.hasNextLine()) {

            var name = scanner.findInLine("Name: (\\w+\\s+\\w+)");
            var age = scanner.findInLine("Age: (\\d+)");
            var city = scanner.findInLine("City: (\\w+)");

            if (name != null) {
                System.out.printf("%s, %s, %s%n",
                        name.replace("Name: ", ""), age, city);
            }

            if (scanner.hasNextLine()) {
                scanner.nextLine();
            }
        }
    }
}

The findInLine method applies a regular expression to the current line and returns the matched text, or null if no match is found.

$ java Main.java
John Doe, Age: 34, City: Bratislava
Jane Doe, Age: 28, City: Prague

Using Locale-aware scanning

The useLocale method configures locale-specific formatting for parsing numbers, such as decimal separators.

Main.java
import java.util.Locale;

void main() {

    var data = "3.14 2,718 1,5";

    try (var scanner = new Scanner(data)) {

        // default locale uses dot as decimal separator
        scanner.useLocale(Locale.US);
        System.out.printf("US: %.2f%n", scanner.nextDouble());
        System.out.printf("US: %.2f%n", scanner.nextDouble());

        // German locale uses comma as decimal separator
        scanner.useLocale(Locale.GERMAN);
        System.out.printf("DE: %.2f%n", scanner.nextDouble());
    }
}

The Locale.US interprets the dot as a decimal separator, while Locale.GERMAN uses the comma. This is important when parsing internationalized data.

$ java Main.java
US: 3.14
US: 2.72
DE: 1.50

The skip method

The skip method skips input that matches a given pattern, useful for ignoring headers or unwanted sections.

Main.java
void main() {

    var data = """
            === Data Start ===
            10 20 30
            40 50 60
            === Data End ===
            """;

    try (var scanner = new Scanner(data)) {

        // skip the header line
        scanner.skip("=== Data Start ===\\s*");

        while (scanner.hasNextInt()) {
            var value = scanner.nextInt();
            System.out.printf("%d ", value);
        }

        System.out.println();
    }
}

The skip method discards the header line, allowing the Scanner to proceed directly to parsing the numeric data.

$ java Main.java
10 20 30 40 50 60

Reading with radix

The useRadix method sets the default radix for interpreting numeric values. This is useful for parsing hexadecimal, octal, or binary numbers.

Main.java
void main() {

    var hexData = "FF A0 1C 4B";

    try (var scanner = new Scanner(hexData)) {

        scanner.useRadix(16);

        while (scanner.hasNextInt()) {
            var value = scanner.nextInt();
            System.out.printf("%d ", value);
        }

        System.out.println();
    }
}

With radix set to 16, the Scanner interprets hexadecimal values such as FF as decimal 255.

$ java Main.java
255 160 28 75

Handling InputMismatchException

When input does not match the expected type, the Scanner throws InputMismatchException. Proper exception handling ensures robust applications.

Main.java
void main() {

    var data = "42 abc 3.14";

    try (var scanner = new Scanner(data)) {

        while (scanner.hasNext()) {

            try {
                if (scanner.hasNextInt()) {
                    System.out.printf("Int: %d%n", scanner.nextInt());
                } else if (scanner.hasNextDouble()) {
                    System.out.printf("Double: %.2f%n", scanner.nextDouble());
                } else {
                    System.out.printf("Token: %s%n", scanner.next());
                }
            } catch (InputMismatchException e) {
                System.out.printf("Error parsing: %s%n", scanner.next());
            }
        }
    }
}

The safest approach is to use hasNextXxx methods before calling the corresponding nextXxx methods, avoiding exceptions altogether.

$ java Main.java
Int: 42
Token: abc
Double: 3.14

Scanner tokens and streams

The tokens method returns a stream of tokens, enabling functional-style processing of scanner input.

Word frequency counter

The following example tokenizes a sentence and counts how many times each word appears, using Collectors.groupingBy with Collectors.counting.

Main.java
void main() {

    var data = "the sun is bright the moon is pale the grass is green";

    try (var scanner = new Scanner(data)) {

        scanner.tokens()
                .map(String::toLowerCase)
                .collect(Collectors.groupingBy(
                        word -> word, TreeMap::new, Collectors.counting()))
                .forEach((word, count) ->
                        System.out.printf("%-12s %d%n", word, count));
    }
}

The tokens method converts the scanner's input into a Stream<String>. We map each token to lowercase and collect the stream into a TreeMap that groups words and counts their occurrences. The result is printed in alphabetical order.

$ java Main.java
bright        1
grass         1
green         1
is            3
moon          1
pale          1
sun           1
the           3

Filtering and transforming tokens

In this example we parse city-temperature pairs and filter cities whose temperature exceeds 20°C, format the output, and display them in sorted order.

Main.java
void main() {

    var data = "Bratislava 25.3 Prague 18.7 Vienna 22.1 Budapest 20.5";

    try (var scanner = new Scanner(data)) {

        var tokens = scanner.tokens().toList();

        var warmCities = IntStream.range(0, tokens.size())
                .filter(i -> i % 2 == 1)
                .filter(i -> Double.parseDouble(tokens.get(i)) > 20)
                .mapToObj(i -> "%s: %.1f\u00b0C".formatted(
                        tokens.get(i - 1), Double.parseDouble(tokens.get(i))))
                .sorted()
                .toList();

        warmCities.forEach(System.out::println);
    }
}

We collect all tokens into a list, then use IntStream.range to work with index positions. The odd indices contain temperatures; we filter those above 20, format city-temperature pairs, and sort the results.

$ java Main.java
Bratislava: 25.3°C
Budapest: 20.5°C
Vienna: 22.1°C

Grouping and summarizing numeric data

This example reads alternating department-salary pairs and computes the average salary for each department.

Main.java
void main() {

    var data = "IT 45000 IT 52000 HR 38000 HR 41000 IT 49000 HR 39500";

    try (var scanner = new Scanner(data)) {

        var tokens = scanner.tokens().toList();

        var depts = new TreeMap<>(IntStream.range(0, tokens.size())
                .filter(i -> i % 2 == 0)
                .boxed()
                .collect(Collectors.groupingBy(
                        i -> tokens.get(i),
                        Collectors.averagingDouble(
                                i -> Double.parseDouble(tokens.get(i + 1))))));

        depts.forEach((dept, avg) ->
                System.out.printf("%s: $%.2f%n", dept, avg));
    }
}

Even indices hold department names, odd indices hold salaries. We filter for even indices, group by department name, and compute the average of the adjacent salary values using Collectors.averagingDouble.

$ java Main.java
HR: $38833.33
IT: $48666.67

Building a configuration map

Here we parse key-value pairs from a string and collect them into a Map using Collectors.toMap.

Main.java
void main() {

    var data = "host localhost port 5432 user admin timeout 30";

    try (var scanner = new Scanner(data)) {

        var tokens = scanner.tokens().toList();

        var config = IntStream.range(0, tokens.size() - 1)
                .filter(i -> i % 2 == 0)
                .boxed()
                .collect(Collectors.toMap(
                        i -> tokens.get(i),
                        i -> tokens.get(i + 1)));

        config.forEach((key, value) ->
                System.out.printf("%s = %s%n", key, value));
    }
}

Even indices contain keys and odd indices contain values. We use IntStream.range to iterate indices, filter for even positions, and collect the adjacent pairs into a map.

$ java Main.java
host = localhost
port = 5432
timeout = 30
user = admin

Source

Java Scanner - language reference

In this article we have used Java's Scanner class to read and parse input data.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Java tutorials.