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


Réponses:


62

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


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")
}

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()
}

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

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
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.