Keyboard input

Open

1. Reading from the console, standard input

In previous lectures, we got familiar with commands for printing to the screen. For that, we used the print() and println() functions. Simple and convenient.

But, as you probably already suspect, printing to the screen alone is not enough. The goal of most programs is to do something useful for the user. That is why very often you need the user to be able to enter data from the keyboard.

In Kotlin there are 2 functions for reading data from the keyboard:

  • readln() — returns a String (or throws an error)
  • readLine() — returns a String or null

We will start with the simpler option — readln(), and once we cover working with null in Kotlin, you can try the other options too.

2. The readln() function

The readln() function can read one line from standard input (that is, from the keyboard). Usually it looks like this:

Code Explanation
val name = readln()
Read a line of text.
val age = readln().toInt()
Then read one more line and convert it to a number (Int).

It looks simple enough, but is everything really that easy? I think you have a bunch of questions, and we will answer them now. But first, let’s demonstrate an example of a complete program that uses readln():

fun main() {
    val name = readln()
    val age = readln().toInt()

    println("Name: " + name)
    println("Age: " + age)
}

3. Declaring variables and reading data

The first question is: what are these lines val name = readln() and val age = readln().toInt()?

As you hopefully remember, in Kotlin variables are usually declared using val (immutable) or var (mutable). Reading a line works the same way:

val name = readln()
Declaring and initializing a variable by reading from the console

Everything to the left of the equals sign is the declaration of a variable named name. You could have named it, for example, s or userName, or even keyboardInput. Then the code would look like this:

val s = readln()
val userName = readln()
val keyboardInput = readln()

I think it is much clearer now. And the code on the right side of the equals sign is not complicated either:

  • readln() — reads a string from the console;
  • .toInt() — tries to convert the string to an integer.

After these lines run, we will have variables that our program can use to work with the data entered by the user.

4. Reading input from the console

Reading input from the keyboard using readln() is very easy.

To read a string from the keyboard, you need this command:

val str = readln()

When the program reaches this line, it will pause and wait until the user enters data and presses the Enter key. After that, everything the user typed will be saved into the str variable.

To read a number from the keyboard, it is usually done like this:

val number = readln().toInt()

Everything here is similar to the previous command. When the program reaches this line, it will pause and wait until the user enters data and presses Enter. After that, everything the user typed will be converted to a number and saved into the number variable.

If the user enters data that cannot be converted to an integer, the program will throw an error (usually NumberFormatException) and will terminate.

To read a fractional number from the keyboard, you need this command:

val number = readln().toDouble()

This command is completely analogous to toInt(), except that it converts the string to a Double.

An example program that reads two numbers from the keyboard and prints their sum:

fun main() {
    val a = readln().toInt()
    val b = readln().toInt()

    println(a + b)
}

5. trim(): what it does and why you need it

trim() is a function on String that removes whitespace at the edges of a string: on the left and on the right. Imagine the string is a doormat at the entrance, and spaces are dirt on your shoes. trim() is like quickly “knocking your boots,” so you do not track junk all over the house (that is, the code).

The main advantage of trim() is that it is a very cheap action for a programmer’s brain: one function call, and you have already protected yourself from half of the “why won’t it parse?!” moments. It is especially useful before toInt()/toIntOrNull(), because the string " 42 " looks like a number, but to the parser it is no longer a “clean” format.

We are not reading input from the console yet (that will be the next lecture), so we will imitate “raw input” using regular string literals.

fun main() {
    val raw = "   42   "
    val cleaned = raw.trim()

    println("raw='$raw'")         // raw='   42   '
    println("cleaned='$cleaned'") // cleaned='42'
}

Notice the trick with quotes: when we print a string as '$raw', spaces become visible; otherwise you would just see “42” and think there are no spaces (but they are sitting there quietly, smiling).

trim() is not magic: what it does not do

Beginners often have a natural dream: “I’ll call trim() and the string will become perfect.” But trim() is not a full deep clean of an apartment; it is just “sweeping the porch.” It does not remove spaces inside a string, because sometimes those spaces are part of the meaning: "Hello world" must not turn into "Helloworld".

This is very important; otherwise you can accidentally corrupt data. For example, the name "Ada Lovelace" with a space inside is a normal name, and removing that space means breaking reality (and reality is fragile enough already).

Let’s look at an example where the space inside remains:

fun main() {
    val raw = "  10 20  "
    val cleaned = raw.trim()

    println("raw='$raw'")         // raw='  10 20  '
    println("cleaned='$cleaned'") // cleaned='10 20'
}

See it? The edges got cleaned up, the middle stayed. And that is correct.

6. Input/output scenarios

Scenario 1: “Polite introduction”

Let’s make the friendliest scenario: the program asks for a name and age (for now, you can keep age as text to avoid complications), and then prints a message.

A key habit here is: each input is its own variable. Do not try to “read twice and forget,” or you will lose the thread of the conversation yourself.

fun main() {
    print("What is your name? ")
    val name = readln().trim()

    print("How old are you (text is OK)? ")
    val ageText = readln().trim()

    println("Hi, $name! You're '$ageText' — sounds solid.")
    // for example: Hi, Ada! You're '20' — sounds solid.
}

Why is trim() useful here even for a name? Because people sometimes enter an accidental trailing space (especially on phones), and then the name will be "Ada " — and that will look weird in the output.

Scenario 2: “Mini calculator”

Let’s assemble a small program that asks for two integers and prints the results of several operations. There is a nuance here: if we use toInt(), the program may crash on bad input; if we use toIntOrNull(), we will get null, but we won’t be able to calculate normally without additional topics (branching, error handling). So we’ll do two versions: “strict” and “observant.”

Strict version

Here we bet on user discipline. This is fine for a learning example: you will see what the “happy path” looks like.

fun main() {
    print("a: ")
    val a = readln().trim().toInt()

    print("b: ")
    val b = readln().trim().toInt()

    println("a + b = ${a + b}") // for example: a + b = 13
    println("a - b = ${a - b}")
    println("a * b = ${a * b}")
}

An important note: division / and remainder % are something we can do technically, but division by zero “breaks” execution. We do not yet know how to protect against that nicely without future tools, so in today’s lecture it’s better not to provoke a / b in interactive input.

Observant version

Now let’s make a version that does not crash on bad input and helps you understand what you actually got from input.

fun main() {
    print("Enter a: ")
    val aText = readln()
    val a: Int? = aText.trim().toIntOrNull()

    print("Enter b: ")
    val bText = readln()
    val b: Int? = bText.trim().toIntOrNull()

    println("aText='$aText' -> a=$a") // for example: aText=' 7 ' -> a=7
    println("bText='$bText' -> b=$b") // for example: bText='q' -> b=null
}

This looks “boring” because we are not calculating. But pedagogically, it is an honest step: you are learning to build input in a way that makes the program predictable and does not turn it into a lottery of “crash / no crash.”

Scenario 3: “Cafeteria checkout”

Let’s build a mini-app that already resembles a real task: there is a product (text), a price and a quantity (numbers), and you need to print the total.

To avoid getting stuck on error handling, we’ll take the strict path (toInt()), but we will be disciplined about trim() and careful with output via templates.

fun main() {
    print("Product name: ")
    val title = readln().trim()

    print("Price (integer): ")
    val price = readln().trim().toInt()

    print("Quantity (integer): ")
    val qty = readln().trim().toInt()

    val total = price * qty
    println("Product: $title")                 // for example: Product: Bun
    println("Total: $qty * $price = $total") // Total: 2 * 35 = 70
}

Here you use almost everything from earlier:

  • a string comes in via readln();
  • we normalize it via trim();
  • we get numbers via toInt();
  • we calculate using Int (*);
  • we output via templates ${...}.

7. Input debugging and a cheat sheet

Observable input: spaces, quotes, and string length

Sometimes a program “doesn’t work,” but in reality you just do not see what exactly arrived in the input. Spaces are champions of stealth: they exist, but you can’t see them. That is why, in learning examples, it is useful to print strings in quotes and sometimes show length.

fun main() {
    print("Enter something (I'll show the length): ")
    val raw = readln()
    val cleaned = raw.trim()

    println("raw='$raw' (len=${raw.length})")
    println("cleaned='$cleaned' (len=${cleaned.length})")
}

If you enter three spaces and press Enter, raw.length will be 3, and cleaned.length will become 0. This directly confirms that trim() removes spaces at the edges.

Function cheat sheet

Sometimes it is useful to put together a “card” of tools, so your brain does not have to keep everything in a fog.

Tool What it does What it returns
print("...")
prints without a newline (handy for prompts)
Unit
println("...")
prints with a newline
Unit
readln()
reads one line up to Enter
String
trim()
removes spaces at the edges of a string
String
toInt()
strictly parses a string as Int
Int
(or an error at runtime)
toIntOrNull()
tries to parse a string as Int
Int?
(a number or null)
"x = $x, sum=${a+b}"
inserts values into text (templates)
String
1
Task
Kotlin SELF,  2 level,  5 lecture
Locked
Chat with a bot
Chat with a bot
1
Task
Kotlin SELF,  2 level,  5 lecture
Locked
Input magnifier
Input magnifier
1
Task
Kotlin SELF,  2 level,  5 lecture
Locked
Elevator number
Elevator number
1
Task
Kotlin SELF,  2 level,  5 lecture
Locked
Parsing log
Parsing log
Комментарии
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны sign in
This page has no comments yet