Чтобы расширить предыдущий ответ, речь идет о том, как обрабатывать null
с.
Проблема в том, что readLine()
может вернуть null
.(Это происходит, если достигнут конец файла; например, если вы перенаправляете ввод из файла и достигаете конца файла; или если он принимает ввод с клавиатуры и нажимаете Ctrl + D.)
Компилятор Kotlin это знает.(Обнуляемость встроена в систему типов Kotlin. readLine()
возвращает String?
- знак вопроса указывает, что значение может быть null
.)
Kotlin очень осторожен в отношении нулевой безопасности и выиграл 'Позволяет вам делать что-либо со значением, которое не сработает, если оно null
.Таким образом, в вашем коде, если вы пропустите !!
, вы получите ошибку в следующем .
.(«Только ненулевые (?.) Или ненулевые утвержденные (!!.) Вызовы разрешены для ненулевого приемника типа String?»)
Так что вам нужно как-то обработать null
.
Добавление ненулевого утверждения !!
эффективно обещает компилятору, что вы знаете лучше, и что он никогда не может быть нулевым.Обычно это плохая идея (именно поэтому этот оператор был разработан, чтобы выглядеть ужасно);на практике вы, как правило, не знаете лучше, чем компилятор, и он вас запутает - как вы обнаружили!В вашем случае readLine()
сделал вернул null
, и поэтому оператор !!
бросил KotlinNullPointerException
.
Итак, вам нужен лучший способ справиться с этим.
Традиционный способ - это явная проверка, например:
val line = readLine()
if (line != null) {
// Within this block, the compiler knows that line
// cannot be null.
} else {
println("No values given.")
}
Это хороший, ясный, общий подход.И это может быть лучшим подходом в вашем случае.(Тем не менее, вам все равно нужно поймать IndexOutOfBoundsException
.)
Поскольку этот подход может быть немного затянутым, у Kotlin есть некоторые другие инструменты, которые могут быть лучше в определенных ситуациях.Я не думаю, что что-то здесь уместно, но я упомяну некоторые для полноты:
Одним из них является оператор безопасного вызова ?.
, указанный в сообщении об ошибке ипредыдущий ответ.Это делает вызов, только если значение не null
;в противном случае он возвращает null
напрямую.Это может быть очень полезно, но это не простой ответ в этом случае, как показывает ваш комментарий: хотя он избегает попыток split()
null
, вам не удастся деконструировать его в три значения a
, b
и c
.(В конце концов, null
не является массивом.)
Если вы хотите заменить значения по умолчанию на a
, b
и c
, если не было ввода, вы можете использовать безопасныйоператор вызова вместе с оператором элвиса ?:
.Это возвращает левую сторону, если это не null
, иначе правая сторона.Таким образом, вы можете сделать, например:
val (a, b, c) = readLine()?.split(' ')
?: arrayOf("defA", "defB", "defC")
println("Values are $a, $b, and $c.")
В этом случае, если readLine()
вернет строку, split()
будет вызвано для нее;или, если нет, вместо него будет использоваться жестко заданный массив.
Обратите внимание, что это по-прежнему неполное решение, поскольку оно не справится, если вы введете строку, содержащую менее двух пробелов.(Таким образом, вам все равно нужно перехватить IndexOutOfBoundsException
или явно проверить этот случай.)
(Возможно, самое короткое из возможных решений - оставить !!
без изменений и изменить catch
блок, чтобы поймать Exception
, поэтому он поймал бы KotlinNullPointerException
вместе с IndexOutOfBoundsException
. Я не рекомендую этого, потому что это уродливо: никому не понятно, кто читает код, что может произойти и какие исключения вынамереваясь поймать - и это может скрыть другие проблемы в коде, если они также приводят к исключениям.)