Немного поработав с Kotlin, я предполагаю, что вы уже знакомы с операторами ? и !!. Если вы этого не сделали, я бы посоветовал вам добавить этот пост в закладки и прийти еще раз, как только вы приобретете немного больше опыта в основах языка.

Шучу, давайте кратко рассмотрим оба. Если у вас есть переменная, которая может быть null, Kotlin требует, чтобы вы пометили ее как необязательную, добавив вопросительный знак к ее типу:

var person: Person?

Чтобы получить доступ к свойствам и методам переменной person, вы должны либо использовать безопасный оператор вызова (?):

// the end result will either be a value of null, never an NPE
var name = person?.name
// The opertor allows for deep chaining as well
var firstName = person?.name?.firstName

или если вы действительно уверены, что переменная никогда не может быть нулевой, вы можете подтвердить это с помощью not-null-assertion (!!):

// an exception will be thrown if person == null
var name = person!!.name

Разница с Java заключается в том, что за применение not-null-assertion ответственность ложится на вас как на разработчика, а не на компилятор.

Хорошо, а как насчет `!`?

В самом деле, помимо явного указания типа как необязательного (Person?), Kotlin представляет нам еще одного зверя, называемого типом платформы, для которого вместо этого стоит один восклицательный знак (например, Person!). Эта концепция была создана из соображений совместимости при доступе к коду с ненулевых небезопасных платформ, таких как Java. Часто бывает, что при использовании библиотеки Java многие методы возвращают SomeType!, поскольку компилятор Kotlin не может сделать вывод, допускает ли результат значение NULL или нет.

Как разработчик, вы должны относиться к типам платформ почти так же, как к необязательным типам. Они просто раздражают, потому что требуют, казалось бы, ненужного шаблона. Как разработчики Kotlin, мы любим разрабатывать контракты методов вокруг ненулевых значений, избегая необязательных типов как части сигнатуры параметра. Если что-то может быть необязательным, лучше назначить разумное значение по умолчанию, чем принимать необязательный параметр. Поэтому проверки в стиле Java if (person == null), хотя и вполне законны, выглядят очень неэлегантно, и разработчики Kotlin ворчат, когда им приходится их делать.

Если вы работаете с Java API, который возвращает вам SomeType!, который вы затем хотите использовать в каком-то коде Kotlin, ожидая вместо этого SomeType, у вас есть три варианта:

  1. Сделайте null проверку в стиле Java (😒)
  2. Явно / unwrap / переменную, используя !! (но вы должны быть на 100% уверены, что она никогда не вернет null, иначе вы вернетесь в страну Java)
  3. Используйте встроенную функцию let magic

Let принимает лямбда в качестве параметра и передает значение переменной в качестве параметра в эту лямбду. Взгляните на следующий фрагмент кода:

var result = someJavaApi.doSomething() // returns SomeType!
result?.let { someKotlinApi.doSomething(it) } // someKotlinApi.doSomething expects SomeType

Приведенный выше фрагмент кода отлично компилируется и решает проблему с типами платформ. Магия заключается в том, что let будет вызываться только в том случае, если значение result не равно null, иначе его вызов будет вообще пропущен. Если let когда-либо будет достигнут, компилятор Kotlin достаточно умен, чтобы вывести тип it (имя параметра по умолчанию в лямбдах) на SomeType, а не на SomeType! или SomeType?.

Какой подход вы выберете? Дай мне знать в комментариях.

Дальнейшее чтение

Одиночный восклицательный знак в Kotlin - Stack Overflow
Вызов Java из Kotlin - язык программирования Kotlin
let - язык программирования Kotlin
Разница между функциями Kotlin: 'let', «применить, с, запустить и также »

Этот пост изначально был опубликован в моем блоге