Le meilleur moyen d'effectuer un enregistrement nul à Kotlin?

94

Dois-je utiliser double =ou triple =?

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

ou

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

De même pour 'pas égal':

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

ou

if(a != null)  {
//do something
}
pdeva
la source
1
regardez sur le lien: - kotlinlang.org/docs/reference/null-safety.html .............. C'est facile dans Kotlin Docs
sushildlh

Réponses:

62

Les deux approches génèrent le même bytecode afin que vous puissiez choisir ce que vous préférez.

Michael
la source
2
Si je l'ai bien compris, il demande la meilleure façon de vérifier null dans Kotlin, pas quelle approche génère le meilleur byte-code. @ La réponse de BenitoBertoli semble prometteuse, elle réduit le code
standard
148

Une égalité structurelle a == bse traduit par

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

Par conséquent, en comparant à null, l'égalité structurelle a == nullse traduit par une égalité référentielle a === null.

Selon la documentation , il ne sert à rien d'optimiser votre code, vous pouvez donc utiliser a == nullet a != null


noter que si la variable est une propriété mutable, vous ne pourrez pas la transtyper intelligemment en son type non nullable dans l' ifinstruction (car la valeur peut avoir été modifiée par un autre thread) et vous devrez utiliser l'opérateur d'appel sécurisé avec à la letplace.

Opérateur d'appel sécurisé ?.

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


Vous pouvez l'utiliser en combinaison avec l'opérateur Elvis.

Opérateur Elvis ?: (je suppose parce que le point d'interrogation ressemble aux cheveux d'Elvis)

a ?: println("null")

Et si vous souhaitez exécuter un bloc de code

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

Combiner les deux

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")
}
Benito Bertoli
la source
1
pourquoi ne pas utiliser ifpour les vérifications nulles? a?.let{} ?: run{}n'est approprié que dans de rares cas, sinon ce n'est pas idiomatique
voddan
2
@voddan Je ne suggérais pas de ne pas utiliser if pour les nullchèques, je listais d' autres options viables. Bien que je ne sache pas s'il y runa une sorte de pénalité de performance. Je mettrai à jour ma réponse pour la rendre plus claire.
Benito Bertoli
1
@voddan Si aest un var, alors en utilisant la a?.let{} ?: run{}garantie qu'il sera lié correctement dans le letpour toute la portée. Si aest a val, alors il n'y a pas de différence.
madeinqc
1
@madeinqc si a est a val, alors utiliser let est différent et c'est mauvais. J'ai trouvé cet article très bon pour l'expliquer - Kotlin: N'utilisez pas simplement LET pour un contrôle nul .
Sufian
34

Manières Kotlin de gérer null

Opération d'accès sécurisé

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

Laisser fonctionner

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

Sortie anticipée

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

Ombres immuables

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
}

Valeur par défaut

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

Utilisez val au lieu de var

valest en lecture seule, varest modifiable. Il est recommandé d'utiliser autant de propriétés en lecture seule que possible, elles sont thread-safe.

Utiliser lateinit

Parfois, vous ne pouvez pas utiliser de propriétés immuables. Par exemple, cela se produit sur Android lorsqu'une propriété est initialisée lors d'un onCreate()appel. Pour ces situations, Kotlin a une fonction de langage appelée 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()
}
Levon Petrosyan
la source
J'appellerais le dernier "valeur par défaut" (pas elvis), puisque 3/4 d'entre eux utilisent elvis.
AjahnCharles
@AjahnCharles fait sens))
Levon Petrosyan
8

Ajout à @Benito Bertoli,

la combinaison est en fait différente de if-else

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

Le résultat est:

1. it=test

Mais si:

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

Le résultat est:

1. it=test
2. it is null!

Aussi, si vous utilisez d'abord elvis:

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

Le résultat est:

1. it is null!
2. it=kotlin.Unit
BingLi224
la source
5

Vérifiez les méthodes utiles, cela pourrait être utile:

/**
 * 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
}

Voici un exemple possible d'utilisation de ces fonctions:

var s: String? = null

// ...

if (s.isNotNullAndSatisfies{ isEmpty() }{
   // do something
}
Vlad
la source