Статьи Kotlin. Null-безопасность. Операторы "?.", "!!.", "?:"
Post
Cancel

Kotlin. Null-безопасность. Операторы "?.", "!!.", "?:"

В статье про базовый синтаксис Kotlin я кратко затрагивала тему null-безопасности. Но думаю стоит более подробно на этом остановиться. К тому же мной были озвучены не все операторы, которые помогают работать с типами, поддерживающими null.

Напомню, что Kotlin разграничивает типы с поддержкой и без поддержки null- значений. Это означает, что при объявлении переменной, которая может хранить null, нужно явно объявить ее как nullable при помощи символа ?.

1
val languageName: String? = null

Объявляя nullable переменную вы берёте на себя ответственность по проверке её значения. Иначе компилятор будет запрещать вызов функций для таких значений, ведь это может привести к NullPointerException.

Рассмотрим все доступные способы проверки значения на null.


Оператор безопасного вызова “?.”

Оператор безопасного вызова позволяет сказать компилятору, что значением данной переменной может быть null и его стоит проверить перед дальнейшим использованием.

1
languageName?.length

То есть, если значение переменной languageName равно null, то компилятор не будет пытаться определить длину слова, а просто вернёт null.

Если вы хотите вызвать функцию или каким-то другим способом обработать значение отличное от null, то совместно с оператором безопасного вызова используйте функцию let. Всё, что будет указано в функции let выполнится только в том случае, если значение переменной отлично от null.

1
languageName?.let { println(it) }

Оператор “!!”

Данный оператор понравится любителям NullPointerException. Он как бы говорит компилятору, что если значение переменной - null, то ТРЕБУЮ выбросить NullPointerException.

1
2
val languageName: String? = null
val size = languageName!!.length

Использование данного оператора крайне не рекомендуется, потому что (очевидно) это один из немногих способов словить NPE. При его использовании вы должны быть уверены, что значение переменной ни при каких обстоятельствах не может быть null. В противном случае лучше использовать оператор безопасного вызова.


Проверка с помощью if-else

Пожалуй это самый простой способ проверки значения на null и скорее всего будет многим знаком.

1
2
3
4
5
if(languageName != null) {
    print("Name is : $languageName")
} else {
    print("Please enter a valid name")
}

Использование оператора безопасного вызова будет предпочтительнее, так как он позволяет решить проблему меньшим количеством кода. Однако, если со значением переменной производятся какие-то сложные вычисления и перед началом вычислений нужно проверить равно ли оно null, то if-else вполне подойдёт.


Элвис оператор или оператор объединения по null “?:”

Почему Элвис? Потому что кому-то этот оператор напомнил прическу Элвиса Пресли.

Оператор указывается между двумя значениями. Если значение слева от оператора равно null, то применяется значение справа.

1
val size: Int = languageName.length ?: 0

Если значение languageName не равно null, его длина будет присвоена переменной size. Если languageName равно null, тогда будет присвоено значение 0. Но в любом случае переменной size будет присвоено значение типа Int, а не Int?, то есть non-null тип.

Использование данного оператора с функцией let может полностью заменить проверку с помощью оператора if-else.

1
2
3
4
5
6
7
8
9
10
11
12
// с использованием if-else
if(languageName != null) {
    print("Name is : $languageName")
} else {
    print("Please enter a valid name")
}


// Элвис оператор и функция let
languageName?.let {
  print("Name is : $languageName")
} ?: print("Please enter a valid name")

Это не означает, что нужно избавляться от конструкций if-else. Например, я считаю, что if-else выглядит намного понятнее. В общем это дело вкуса.


Вывод

Какой из всего этого можно сделать вывод? Не используйте nullable типы без явной необходимости. А если всё таки решились, то подходите к этому со всей ответственностью и правильно обрабатывайте null-значения при помощи описанных выше способов.


Полезные ссылки

Официальная документация.

Перевод документации на русский.

This post is licensed under CC BY 4.0 by the author.

Kotlin. Отложенная и ленивая инициализация свойств

Kotlin. Функции области видимости (Scope Functions)