6 minutes read

Sometimes, it isn't enough to use readln() to read data from standard input. readln() is a simple method, not suitable for complex tasks, for example: find only Integers or only Doubles in a data flow, read data sequentially, word by word, and control such reading step by step. In this topic, you will learn to use one of Java tools that can be also used in Kotlin — Scanner.

What is Java Scanner?

Scanner is another way to obtain data from standard input. You can access it directly from Kotlin because it is interoperable with other Java libraries. Scanner allows a program to read values of different types (strings, numbers, etc.) from standard input.

To use it, you need to add the following import statement to the top of your file with the source code:

import java.util.Scanner

or

import java.util.*

You can use either method to add Scanner to your program. We will discuss importing in more detail later.

Let's create a variable initialized by Scanner:

val scanner = Scanner(System.`in`)

In this line, System.`in` is an object that represents the standard input stream. scanner wraps it as an internal data source and provides a set of convenient methods to work with it. Sure, you can use Scanner(System.`in`) in your code instead of creating a scanner variable, but using a single variable is a more convenient and readable way to do it.

Now we can read data from standard input:

val line = scanner.nextLine() // read a whole line, e.g., "Hello, Kotlin"
val num = scanner.nextInt()   // read a number, e.g., 123
val string = scanner.next()   // read a string, e.g., "Hello"

scanner.next() reads only one word, not a line. If the user enters Hello, Kotlin, it will read Hello,.

After you call scanner.nextLine() or scanner.nextInt() or something similar, the program will anticipate input data. Here is an example of correct input data:

Hello, Kotlin
123 Hello

The input example below is also valid:

Hello, Kotlin
123
Hello

It's possible to read a number as a string using scanner.next() or scanner.nextLine() if the number is on a new line.

Also, the Scanner type provides several methods (functions) for reading values of other types. Refer to the Class Scanner documentation for more details.

The program below reads two numbers and outputs them in reverse order on two different lines:

import java.util.Scanner // a class (type) from the Java standard library

fun main() {
    val scanner = Scanner(System.`in`) // reads data

    val num1 = scanner.nextInt() // reads the first number
    val num2 = scanner.nextInt() // reads the second number

    println(num2) // prints the second number
    println(num1) // prints the first number
}

Ok, now we've read the data and don't need Scanner anymore. When we used readln(), we just proceeded with our code and moved further. But Scanner can consume PC resources all the time. To stop it, we need to use the method close(), which... cancels Scanner:)

scanner.close()

Now we are good.

Custom delimiter

One important thing: we can input data directly in Scanner. Let's see:

val scanner = Scanner("123_456")

But how can we read next word if we don't have whitespaces or new lines? For these cases, Scanner has a convenient tool — useDelimiter(). With its help, we can customize our delimiters for methods like next(), nextInt(), etc. (the default value of delimiter is a whitespace).

To read these words and integers separately, we have to set a new delimiter symbol – "_":

scanner.useDelimiter("_")

Now, we can read this data:

println(scanner.nextInt()) // 123
println(scanner.nextInt()) // 456

Cool!

Check next element

Suppose we have the following data on our Scanner:

val scanner = Scanner("Hello, Kotlin!")

Now, we try to read several words:

val word1 = scanner.next()
val word2 = scanner.next()
val word3 = scanner.next()

When we try to read the third word, we'll receive an exception and our program will crash. What can we do with that? Huh, Scanner has its own method for such a situation – it is called hasNext() (hasNextInt(), etc).

if (scanner.hasNext()) val word1 = scanner.next() // Hello,
if (scanner.hasNext()) val word2 = scanner.next() // Kotlin!
if (scanner.hasNext()) val word3 = scanner.next() // It doesn't work but also doesn't make error

Now, we are able to read data or not to read it if our data flow has ended.

Conclusion

In this topic, we have discussed the second way to read from standard input — Java Scanner. It is a convenient way to read complex data and filter content. Here's what you need to remember:

  1. If Scanner isn't needed, always use readln().

  2. To read different types of data, Scanner has methods like next(), nextInt(), and nextLine().

  3. If you have input with strange delimiters, use the method useDelimiter().

  4. If you don't know how many words the input has, use the method hasNext().

2056 learners liked this piece of theory. 206 didn't like it. What about you?
Report a typo