JavaRush /Курси /Kotlin SELF /Введення з клавіатури

Введення з клавіатури

Kotlin SELF
Рівень 2 , Лекція 5
Відкрита

1. Читання з консолі, стандартне введення

У попередніх лекціях ми познайомилися з командами виведення на екран. Для цього використовували функції print() і println(). Просто й зручно.

Але, як ви вже, напевно, здогадуєтеся, одного лише виведення на екран недостатньо. Мета більшості програм — зробити щось корисне для користувача. Тому дуже часто потрібно, щоб користувач міг вводити дані з клавіатури.

У Kotlin є 2 функції для читання даних із клавіатури:

  • readln() — повертає String (або помилку)
  • readLine() — повертає String або null

Почнемо з простішого варіанта — readln(). А коли розберемося з роботою з null у Kotlin, спробуємо й інші варіанти.

2. Функція readln()

Функція readln() вміє зчитувати один рядок зі стандартного введення (тобто з клавіатури). Зазвичай це виглядає так:

Код Пояснення
val name = readln()
Читаємо рядок тексту.
val age = readln().toInt()
Потім читаємо ще один рядок і перетворюємо його на число (Int).

Зовні все виглядає нескладно. Та чи справді тут немає підводних каменів? Гадаю, у вас уже зʼявилася купа запитань — і зараз ми на них відповімо. А для початку подивімося на приклад повної програми, у якій використовується readln():

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

    println("Імʼя: " + name)
    println("Вік: " + age)
}

3. Оголошення змінних і читання даних

Перше запитання: що це за рядки val name = readln() і val age = readln().toInt()?

Як ви, сподіваюся, уже запамʼятали, у Kotlin змінні зазвичай оголошують за допомогою val (незмінна) або var (змінна). Так само працює й читання рядка:

val name = readln()
Оголошення та ініціалізація змінної через читання з консолі

Усе, що розташовано ліворуч від знака дорівнює, — це оголошення змінної з імʼям name. Можна було назвати її, наприклад, s або userName, або навіть keyboardInput. Тоді код виглядав би так:

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

Думаю, тепер усе стало значно зрозуміліше. А код праворуч від знака дорівнює теж не містить нічого складного:

  • readln() — читає рядок із консолі;
  • .toInt() — намагається перетворити рядок на ціле число.

Після виконання цих рядків у нас зʼявляться змінні, за допомогою яких програма зможе використати дані, введені користувачем.

4. Введення даних із консолі

Вводити дані з клавіатури за допомогою readln() дуже легко.

Щоб зчитати з клавіатури рядок, потрібна команда:

val str = readln()

Коли програма дійде до виконання цього рядка, вона зупиниться й чекатиме, доки користувач уведе дані та натисне клавішу Enter. Після цього все, що ввів користувач, буде збережено в змінну str.

Щоб зчитати з клавіатури число, зазвичай роблять так:

val number = readln().toInt()

Тут усе аналогічно попередній команді. Коли програма дійде до виконання цього рядка, вона зупиниться й чекатиме, доки користувач уведе дані та натисне клавішу Enter. Після цього все, що ввів користувач, буде перетворено на число й збережено в змінну number.

Якщо користувач увів дані, які неможливо перетворити на ціле число, у програмі виникне помилка (зазвичай це NumberFormatException), і вона завершиться.

Щоб зчитати з клавіатури дробове число, потрібна команда:

val number = readln().toDouble()

Ця команда повністю аналогічна перетворенню toInt(), тільки вона перетворює рядок на число Double.

Приклад програми, яка зчитує з клавіатури два числа й виводить їхню суму:

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

    println(a + b)
}

5. trim(): що робить і навіщо потрібен

trim() — це функція класу String, яка прибирає пробільні символи на краях рядка: ліворуч і праворуч. Уявіть, що рядок — це килимок біля входу, а пробіли — бруд на взутті. trim() — це ніби швидко «обстукати черевики», щоб далі по дому (тобто по коду) не розносити сміття.

Головна перевага trim() у тому, що це дія, яка майже не потребує зусиль: одна функція — і ви вже захистилися від половини ситуацій із серії «чому воно не перетворюється?!». Особливо корисно робити так перед toInt()/toIntOrNull(), адже рядок " 42 " виглядає як число, але для перетворювача це вже не «чистий» формат.

Зараз ми ще не читаємо введення з консолі (це буде наступна лекція), тому імітуватимемо «сире введення» звичайними рядковими літералами.

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

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

Зверніть увагу на прийом із лапками: коли ми друкуємо рядок як '$raw', пробіли стають видимими. Інакше ви просто побачите «42» і подумаєте, що пробілів немає (а вони там тихенько є).

trim() не чарівник: чого він не робить

У новачків є природна мрія: «зараз застосую trim(), і рядок стане ідеальним». Але trim() — не генеральне прибирання квартири, а лише «підмести біля порога». Він не видаляє пробіли всередині рядка, бо інколи ці пробіли є частиною сенсу: "Hello world" не повинен перетворюватися на "Helloworld".

Це важливо: інакше ви можете випадково зіпсувати дані. Наприклад, імʼя "Ada Lovelace" із пробілом усередині — це нормальне імʼя. А прибрати пробіл означає спотворити введення (а дані й так часто крихкі).

Подивімося на приклад, у якому пробіл усередині лишається:

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

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

Бачите: краї очистилися, середина лишилася. І це правильно.

6. Сценарії введення/виведення

Сценарій 1: «Ввічливе знайомство»

Зробімо найпривітніший сценарій: програма запитує імʼя та вік (вік поки що можна залишити текстом, щоб не ускладнювати), а потім друкує повідомлення.

Тут важлива звичка: кожне введення — окрема змінна. Не намагайтеся «прочитати двічі й забути», інакше ви самі загубите нитку розмови.

fun main() {
    print("Як вас звати? ")
    val name = readln().trim()

    print("Скільки вам років (можна текстом)? ")
    val ageText = readln().trim()

    println("Привіт, $name! Вам '$ageText' — звучить солідно.")
    // наприклад: Привіт, Ada! Вам '20' — звучить солідно.
}

Чому trim() тут корисний навіть для імені? Тому що люди іноді випадково ставлять пробіл у кінці (особливо на телефоні). Тоді імʼя буде "Ada " — і у виведенні це виглядатиме дивно.

Сценарій 2: «Мінікалькулятор»

Зберімо маленьку програму, яка просить два цілі числа й друкує результати кількох операцій. Тут є тонкість: якщо ми використовуємо toInt(), програма може впасти на некоректному введенні. А якщо використовуємо toIntOrNull(), отримаємо null, але не зможемо нормально порахувати без додаткових тем (розгалуження, обробка помилок). Тому зробимо два варіанти: «суворий» і «спостережливий».

Суворий варіант

Тут ми робимо ставку на дисципліну користувача. Для навчального прикладу це нормально: ви побачите, як виглядає «щасливий шлях».

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

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

    println("a + b = ${a + b}") // наприклад: a + b = 13
    println("a - b = ${a - b}")
    println("a * b = ${a * b}")
}

Важлива ремарка: ділення / і остача % нам технічно доступні, але ділення на нуль «ламає» виконання. Поки що ми не вміємо надійно захищатися від цього без інструментів із наступних тем, тому в сьогоднішній лекції краще не провокувати a / b в інтерактивному введенні.

Спостережливий варіант

Тепер зробимо версію, яка не падає на некоректному введенні й допомагає зрозуміти, що насправді вийшло після читання.

fun main() {
    print("Введіть a: ")
    val aText = readln()
    val a: Int? = aText.trim().toIntOrNull()

    print("Введіть b: ")
    val bText = readln()
    val b: Int? = bText.trim().toIntOrNull()

    println("aText='$aText' -> a=$a") // наприклад: aText=' 7 ' -> a=7
    println("bText='$bText' -> b=$b") // наприклад: bText='q' -> b=null
}

Це виглядає «нудно», бо ми не рахуємо. Зате з погляду навчання це чесний крок: ви вчитеся будувати введення так, щоб програма була передбачуваною й не перетворювалася на лотерею «впаде / не впаде».

Сценарій 3: «Каса в їдальні»

Зберімо мінізастосунок, який уже схожий на реальну задачу: є товар (текст), є ціна і кількість (числа), і потрібно вивести суму.

Щоб не впиратися в обробку помилок, підемо суворим шляхом (toInt()). Водночас будемо дисципліновано застосовувати trim() і акуратно виводити результат за допомогою шаблонів рядків.

fun main() {
    print("Назва товару: ")
    val title = readln().trim()

    print("Ціна (ціле число): ")
    val price = readln().trim().toInt()

    print("Кількість (ціле число): ")
    val qty = readln().trim().toInt()

    val total = price * qty
    println("Товар: $title")                 // наприклад: Товар: Булочка
    println("Разом: $qty * $price = $total") // Разом: 2 * 35 = 70
}

Тут ви використовуєте майже все, що було раніше:

  • рядок приходить через readln();
  • ми нормалізуємо його через trim();
  • числа отримуємо через toInt();
  • рахуємо на Int (*);
  • виводимо через шаблони рядків ${...}.

7. Налагодження введення та шпаргалка

Спостережуване введення: пробіли, лапки та довжина рядка

Іноді програма «не працює», але насправді ви просто не бачите, що саме прийшло у введенні. Пробіли — чемпіони з непомітності: вони є, але їх не видно. Тому в навчальних прикладах корисно друкувати рядки в лапках і часом показувати length.

fun main() {
    print("Введіть що-небудь (я покажу довжину): ")
    val raw = readln()
    val cleaned = raw.trim()

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

Якщо ви введете три пробіли й натиснете Enter, то raw.length буде 3, а cleaned.length стане 0. Це пряме підтвердження того, що trim() прибирає пробіли на краях.

Шпаргалка з функцій

Іноді корисно зібрати «картку» з інструментів, щоб не тримати все в голові й не плутатися.

Інструмент Що робить Що повертає
print("...")
друкує без перенесення рядка (зручно для підказки)
Unit
println("...")
друкує з перенесенням рядка
Unit
readln()
читає один рядок до Enter
String
trim()
прибирає пробіли на краях рядка
String
toInt()
суворо перетворює рядок на Int
Int
(або помилка під час запуску)
toIntOrNull()
намагається перетворити рядок на Int
Int?
(число або null)
"x = $x, sum=${a+b}"
вставляє значення в текст (шаблони рядків)
String
1
Опитування
Цілі числа, рядки та введення даних, рівень 2, лекція 5
Недоступний
Цілі числа, рядки та введення даних
Цілі числа, рядки та введення даних
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ