Лучший способ обнулить проверку в Котлине?

98

Я должен использовать двойной =или тройной =?

if(a === null)  {
//do something
}

или

if(a == null)  {
//do something
}

Аналогично для «не равно»:

if(a !== null)  {
//do something
}

или

if(a != null)  {
//do something
}
пдева
источник
1
посмотрите ссылку: - kotlinlang.org/docs/reference/null-safety.html .............. Это просто в Kotlin Docs
sushildlh

Ответы:

63

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

Майкл
источник
4
Если я правильно понял, то он спрашивает, как лучше всего проверить значение null в Kotlin, а не какой подход генерирует лучший байт-код. Ответ @ BenitoBertoli выглядит многообещающим, он сокращает шаблонный код
imGs
156

Структурное равенство a == bпереводится как

a?.equals(b) ?: (b === null)

Следовательно, при сравнении с null, структурное равенство a == nullпереводится в ссылочное равенство a === null.

Согласно документам , нет смысла оптимизировать ваш код, поэтому вы можете использовать a == nullи a != null


обратите внимание, что если переменная является изменяемым свойством, вы не сможете интеллектуально преобразовать ее в ее тип, не допускающий значения NULL внутри ifоператора (потому что значение могло быть изменено другим потоком), и вам придется использовать letвместо него безопасный оператор вызова .

Оператор безопасного звонка ?.

a?.let {
   // not null do something
   println(it)
   println("not null")
}


Вы можете использовать его в сочетании с оператором Элвиса.

Оператор Элвиса ?: (я предполагаю, потому что знак допроса похож на волосы Элвиса)

a ?: println("null")

И если вы хотите запустить блок кода

a ?: run {
    println("null")
    println("The King has left the building")
}

Сочетание двух

a?.let {
   println("not null")
   println("Wop-bop-a-loom-a-boom-bam-boom")
} ?: run {
    println("null")
    println("When things go null, don't go with them")
}
Бенито Бертоли
источник
1
почему бы вам не использовать ifдля нулевых проверок? a?.let{} ?: run{}уместно только в редких случаях, иначе это не идиоматика
voddan
2
@voddan Я не предлагал не использовать if для nullпроверок, я перечислял другие жизнеспособные варианты. Хотя я не уверен, runесть ли какое-то снижение производительности. Я обновлю свой ответ, чтобы было понятнее.
Бенито Бертоли
1
@voddan Если aэто a var, то с использованием a?.let{} ?: run{}гарантии, что он будет правильно привязан letдля всей области. Если aесть val, то разницы нет.
madeinqc
1
@madeinqc, если a - это val, то использование let отличается, и это плохо. Я нашел эту статью очень хорошей для объяснения этого - Kotlin: не используйте LET только для проверки нуля .
Суфьян
39

Kotlin способы обработки null

Безопасный доступ

val dialog : Dialog? = Dialog()
dialog?.dismiss()  // if the dialog will be null,the dismiss call will be omitted

Пусть функция

user?.let {
  //Work with non-null user
  handleNonNullUser(user)
}

Ранний выход

fun handleUser(user : User?) {
  user ?: return //exit the function if user is null
  //Now the compiler knows user is non-null
}

Неизменяемые тени

var user : User? = null

fun handleUser() {
  val user = user ?: return //Return if null, otherwise create immutable shadow
  //Work with a local, non-null variable named user
}

Значение по умолчанию

fun getUserName(): String {
 //If our nullable reference is not null, use it, otherwise use non-null value 
 return userName ?: "Anonymous"
}

Используйте val вместо var

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

Используйте lateinit

Иногда нельзя использовать неизменяемые свойства. Например, это происходит на Android, когда при onCreate()вызове инициализируется какое-то свойство . Для таких ситуаций в Kotlin есть языковая функция под названием lateinit.

private lateinit var mAdapter: RecyclerAdapter<Transaction>

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   mAdapter = RecyclerAdapter(R.layout.item_transaction)
}

fun updateTransactions() {
   mAdapter.notifyDataSetChanged()
}
Левон Петросян
источник
Я бы назвал последнее «значением по умолчанию» (не elvis), поскольку 3/4 из них используют elvis.
AjahnCharles
@AjahnCharles имеет смысл))
Левон Петросян
1
это мусор, любой современный язык может лучше справиться с опциями, чем этот. для программистов это скорее работа, чем польза.
JBarros35,
10

Дополнение к @Benito Bertoli,

комбинация на самом деле не похожа на if-else

"test" ?. let {
    println ( "1. it=$it" )
} ?: let {
    println ( "2. it is null!" )
}

Результат:

1. it=test

Но если:

"test" ?. let {
    println ( "1. it=$it" )
    null // finally returns null
} ?: let {
    println ( "2. it is null!" )
}

Результат:

1. it=test
2. it is null!

Также, если сначала использовать elvis:

null ?: let {
    println ( "1. it is null!" )
} ?. let {
    println ( "2. it=$it" )
}

Результат:

1. it is null!
2. it=kotlin.Unit
BingLi224
источник
5

Ознакомьтесь с полезными методами, они могут быть полезны:

/**
 * Performs [R] when [T] is not null. Block [R] will have context of [T]
 */
inline fun <T : Any, R> ifNotNull(input: T?, callback: (T) -> R): R? {
    return input?.let(callback)
}

/**
 * Checking if [T] is not `null` and if its function completes or satisfies to some condition.
 */
inline fun <T: Any> T?.isNotNullAndSatisfies(check: T.() -> Boolean?): Boolean{
    return ifNotNull(this) { it.run(check) } ?: false
}

Ниже приведен возможный пример использования этих функций:

var s: String? = null

// ...

if (s.isNotNullAndSatisfies{ isEmpty() }{
   // do something
}
Влад
источник