1. Introduction
When we learn a new programming language, it’s common to start with console I/O. In this tutorial, we’ll explore some alternatives for handling console I/O with Kotlin.
2. Using the Kotlin Standard Library
The Kotlin standard library provides us extensions for handling I/O based on the JDK’s built-in support.
To print to the console, we can use the print() function. Let’s run the following snippet:
print("Hello from Kotlin")
We’ll see the following message displayed on our terminal:
Hello from Kotlin
Behind the scenes, this function uses Java’s System.out.print() method. Also, the library offers us the println() alternative function, which adds the line separator at the end of the message.
In order to read from the console, we can use the readln() and readlnOrNull() functions. As such, we can use either of these functions to read a line from stdin and get the value in return. Let’s verify this behavior:
@Test
fun givenInput_whenReadln_thenReadText() {
val expectedInput = "Hello from Kotlin"
val input = ByteArrayInputStream(expectedInput.toByteArray())
System.setIn(input)
val readText = readln()
assertThat(readText).isEqualTo(expectedInput)
}
@Test
fun givenInput_whenReadlnOrNull_thenReadText() {
val expectedInput = "Hello from Kotlin"
val input = ByteArrayInputStream(expectedInput.toByteArray())
System.setIn(input)
val readText = readlnOrNull()
assertThat(readText).isEqualTo(expectedInput)
}
However, the behaviors of readln() and readlnOrNull() functions differ for the scenario when EOF is reached. While readln() throws RunTimeException, the readlnOrNull() function returns a null value. Let’s see this scenario and their differing behavior in action:
@Test
fun givenEofReachedInput_whenReadln_thenThrowsRunTimeException() {
assertThrows<RuntimeException> {var readText = readln()}
}
@Test
fun givenEofReachedInput_whenReadlnOrNull_thenReadNull() {
val readText = readlnOrNull()
assertThat(readText).isEqualTo(null)
}
We must note that readln() and readlnOrNull() are only available in Kotlin 1.6.0 and above. If we’re using an older version in the project, then we can use the readLine() function:
val inputText = readLine()
Interestingly, *this isn’t a synonym for Scanner.readLine() like print() is for System.out.print().* In the next section, we’ll see where Scanner does come in, though.
3. Using the Java Standard Library
Kotlin has great interoperability with Java. Thus, we can use the standard I/O classes from the JDK in our programs in case we need them.
Let’s explore some of them here.
3.1. Using the Scanner Class
Using the Scanner class is very straightforward; we only need to create an instance and use the nextLine() method:
val scanner = Scanner(System.`in`)
val readText = scanner.nextLine()
Notably, we’re escaping the in property with backticks because it’s a keyword in Kotlin.
3.2. Using the BufferedReader Class
To use the BufferedReader class to read from the standard input stream, we first need to instantiate it with System.in:
val reader = BufferedReader(InputStreamReader(System.`in`))
And then we can use its methods — for example, readLine():
val readText = reader.readLine()
3.3. Using the Console Class
Unlike the two previous classes, the Console class has additional methods for handling console I/O, like readPassword() and printf().
In order to use the Console class, we need to get an instance from the System class:
val console = System.console()
Now, we can use its readLine() method, among others:
val readText = console.readLine()
4. Conclusion
In this article, we learned how to handle I/O with Kotlin and how to use the equivalent classes from the JDK. For more details about these JDK classes, be sure to check out our tutorial on Scanner, BufferedReader, and Console.
Also, thanks to Kotlin’s interoperability with Java, we can use additional Java libraries for handling I/O.
As usual, all the code samples shown in this article are available over on GitHub.