¿La mejor manera de hacer check-in nulo en Kotlin?

98

¿Debería usar doble =o triple =?

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

o

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

De manera similar para 'no es igual a':

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

o

if(a != null)  {
//do something
}
pdeva
fuente
1
eche un vistazo al enlace: - kotlinlang.org/docs/reference/null-safety.html .............. Es fácil en Kotlin Docs
sushildlh

Respuestas:

63

Ambos enfoques generan el mismo código de bytes para que pueda elegir lo que prefiera.

Miguel
fuente
4
. Si lo entendí correctamente, entonces él está pidiendo a la mejor manera de comprobar nulo en Kotlin, no cuál es el enfoque genera mejor código de bytes @ BenitoBertoli miradas respuesta prometedora, es reduce código repetitivo
IMGS
155

Una igualdad estructural a == bse traduce en

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

Por tanto, al comparar con null, la igualdad estructural a == nullse traduce en una igualdad referencial a === null.

De acuerdo con los documentos , no tiene sentido optimizar su código, por lo que puede usar a == nully tenga en a != null


cuenta que si la variable es una propiedad mutable, no podrá convertirla de manera inteligente en su tipo no anulable dentro de la ifdeclaración (porque el valor podría haber sido modificado por otro hilo) y tendría que usar el operador de llamada segura con en su letlugar.

Operador de llamada segura ?.

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


Puede usarlo en combinación con el operador de Elvis.

Operador de Elvis ?: (supongo que porque la marca de interrogación se parece al cabello de Elvis)

a ?: println("null")

Y si quieres ejecutar un bloque de código

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

Combinando los dos

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
fuente
1
¿Por qué no lo usas ifpara cheques nulos? a?.let{} ?: run{}solo es apropiado en casos raros, de lo contrario no es idiomático
voddan
2
@voddan No estaba sugiriendo no usar si para los nullcheques, estaba enumerando otras opciones viables. Aunque no estoy seguro de si runtiene algún tipo de penalización de rendimiento. Actualizaré mi respuesta para que quede más claro.
Benito Bertoli
1
@voddan Si aes un var, entonces use la a?.let{} ?: run{}garantía de que se vinculará correctamente en lettodo el alcance. Si aes a val, entonces no hay diferencia.
madeinqc
1
@madeinqc si a es a val, entonces usar let es diferente y es malo. Encontré este artículo muy bueno para explicarlo - Kotlin: No use LET para la verificación nula .
Sufian
39

Maneras de Kotlin de manejar null

Operación de acceso seguro

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

Dejar funcionar

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

Salida anticipada

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

Sombras inmutables

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
}

Valor por defecto

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

Usa val en lugar de var

vales de solo lectura, vares mutable. Se recomienda utilizar tantas propiedades de solo lectura como sea posible, ya que son seguras para subprocesos.

Utilice lateinit

A veces no puedes usar propiedades inmutables. Por ejemplo, sucede en Android cuando alguna propiedad se inicializa en onCreate()call. Para estas situaciones, Kotlin tiene una función de idioma llamada 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
fuente
Yo llamaría al último "valor predeterminado" (no elvis), ya que 3/4 de ellos están usando elvis.
AjahnCharles
@AjahnCharles tiene sentido))
Levon Petrosyan
1
esto es basura, cualquier lenguaje moderno puede lidiar mejor con opcionales que esto. es más una tarea que un beneficio para los programadores.
JBarros35
10

Además de @Benito Bertoli,

la combinación es realmente diferente a if-else

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

El resultado es:

1. it=test

Pero si:

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

El resultado es:

1. it=test
2. it is null!

Además, si usa elvis primero:

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

El resultado es:

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

Compruebe los métodos útiles, podría ser útil:

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

A continuación se muestra un posible ejemplo de cómo utilizar esas funciones:

var s: String? = null

// ...

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