Ошибка Only safe (?.) or non-null asserted (!!.) calls are allowed
Компилятор пишет примерно так:
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?Значит, переменная может оказаться null (её тип со знаком ? — здесь String?), а программа обращается к ней как к обычному значению: s.length, s.uppercase(). Kotlin не даёт собрать такой код, пока не ясно, что делать при null.
Как исправить
fun main() {
val s: String? = readlnOrNull()
// 1. Проверить на null
if (s != null) {
println(s.length)
}
// 2. Безопасный вызов: при null результат — null
println(s?.length)
// 3. Значение по умолчанию
val len = s?.length ?: 0
println(len)
// 4. Выполнить блок, только если не null
s?.let { println(it.uppercase()) }
// 5. «Точно не null» — при null программа упадёт
println(s!!.length)
}Какой способ выбрать:
if (s != null)— когда приnullнужно сделать что-то своё. Внутри проверки компилятор считаетsобычной строкой.s?.length— когдаnullв результате допустим.s?.length ?: 0— когда нужно запасное значение. Справа от?:можно поставить иreturn.s?.let { ... }— когда с непустым значением надо сделать несколько действий.s!!.length— только когдаnullдействительно невозможен. Приnull—NullPointerException.
Подробно — в уроке Null-безопасность.
Частые причины
readLine() вместо readln(). Старая readLine() возвращает String?, поэтому readLine().toInt() не собирается. Возьмите readln() — она возвращает обычную String:
fun main() {
val n = readln().toInt()
println(n * 2)
}2142Значение из словаря. map["key"] имеет тип со знаком ?: ключа может не быть. Используйте map["key"] ?: значение, map.getValue("key") (бросит ошибку, если ключа нет) или map.getOrDefault(...).
Функции с OrNull в имени — toIntOrNull(), firstOrNull(), getOrNull() — возвращают null при неудаче. Это сделано специально: обработайте null через ?:.
Проверка есть, а ошибка осталась
Если s — изменяемое свойство класса (var), проверка if (s != null) не помогает: между проверкой и использованием значение могло измениться. Компилятор пишет, что умное приведение невозможно (smart cast is impossible): даже после проверки он не может считать s обычной строкой. Скопируйте значение в локальную val и работайте с ней:
class Profile {
var nickname: String? = null
fun show() {
val n = nickname
if (n != null) {
println(n.length)
}
}
}Или короче: nickname?.let { println(it.length) }.
Не исправляйте каждую такую ошибку добавлением !! — так ошибка из сборки переезжает в работу программы, и она упадёт у пользователя. !! уместен, только когда null невозможен, а компилятор этого не видит.