Kotlin и работа с NULL

NullPointerException видимо настолько достал, что разработчики Kotlin решили раз и навсегда решить эту проблему наскоком. Теперь при инициализации переменной вы можете указать, что она в какой-то момент может быть null, и при ее использовании вы должны будете это учесть.
Давайте разберем вот этот довольно простой класс
У него есть два свойства — имя, которое не должно быть null, и никнейм, который может быть null (и даже больше — именно это значение указано при инициализации). Все довольно просто, а если вас вдруг смутил модификатор lateinit, то бояться его не стоит от слова совсем — просто предполагается, что перед использованием этого свойства оно будет проинициализировано (а иначе будет бум!)
Давайте сначала рассмотрим работу со свойством nick. Добавим в наш объект метод, определяющий, является ли никнейм одновременно адресом электронной почты
Компилятор сразу же указывает вам на ошибку, подчеркивая точку красным.

Что в переводе на язык начинающего kotlin разработчика означает, что можно использовать либо какой-то знак вопроса, либо двойное восклицание для данного объекта. Почему? А потому, что при описании свойства мы указали, что оно может быть null — об этом говорит знак вопроса после указания типа объекта.
Для того, чтобы компилятор пропустил наше выражение, необходимо его перестроить согласно подсказке. Использование знака вопроса предполагает безопасное использование, то есть если nick = null, то ничего выполняться не будет. В старой доброй Java без проверки на null мы бы получили NPE.
Получить желаемый результат для данного примера можно с использованием модификатора безопасного использования и оператора Элвиса. Смотрим
Читаем практически посимвольно:
Если свойство nick не null, то проверяем, есть ли в нем символ собаки. А если все-таки null, то это точно не email, так что в результате получим false (это то, что после непонятной комбинации “?:” )
Рассмотрим вторую подсказку, та, что с двойным восклицанием. А тут на самом деле все просто. Двойное восклицание в случае если nick = null генерирует старую добрую ошибку.
То есть считается, что это уже дается на ваш, как разработчика, откуп. Хотите — генерируйте NPE Exception. Зато вы точно будете знать где собака порылась. К слову, при конвертации проекта из Java в Kotlin двойное восклицание ставится в большинстве случаев, так что этот момент нужно обязательно учитывать.
К слову, хотя это не очень относится к нашей теме, но все же — если в задаче стоит, что если у вас nickname все таки email, то все что после собаки надо обрезать, то вам поможет функция let. Давайте сначала код, а потом уже разбор.
Значит так. Внутри функции let есть аргумент it, который является ни чем иным, как объектом, к которому применена сама функция. Особенностью этого метода является то, что то что будет записано в последней его строчке, будет являться результатом всей операции. То есть в нашем случае как раз таки — email это или нет. И в ней же мы модифицируем nick — режем все, что после собаки, включая ее саму.
Такая вот хитрость.
Идем дальше. Что там с необъявленным как возможный null свойством name?
Возможно, новая “ошибка на миллион” =)
При использовании не инициализированного свойства, объявленного как lateinit, приложение падает с ошибкой UninitializedPropertyAccessException.
Как решить? Вариантов масса и все они правильные. Если религия вам запрещает объявлять переменную как возможную null (чуть ниже расскажу почему такое может быть), то навскидку варианты следующие:
- Убрать модификатор lateinit и задать начальное значение переменной
- Использовать метод init при создании объекта. Модификатор lateinit при этом тоже уходит в топку
- Использовать дефолтный конструктор с параметром. При этом необходимо присвоить свойству этот параметр, а модификатор lateinit… ну, вы поняли
- Присвоить значение переменной перед ее первым использованием
Пожалуй, на этом хватит. Всем спасибо

