Najlepszy sposób na zerową weryfikację w Kotlinie?


Odpowiedzi:


62

Obie metody generują ten sam kod bajtowy, więc możesz wybrać, co wolisz.


4
Jeśli dobrze to zrozumiałem, to pyta o najlepszy sposób sprawdzenia null w Kotlinie, a nie które podejście generuje najlepszy kod bajtowy. @ BenitoBertoli odpowiedź wygląda obiecująco, zmniejsza standardowy kod
imGs

155

Równość strukturalna a == bjest tłumaczona na

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

Dlatego w porównaniu nullz równością strukturalną a == nullprzekłada się na równość referencyjną a === null.

Zgodnie z dokumentacją nie ma sensu optymalizowanie kodu, więc możesz użyć a == nulli a != null


Zauważ, że jeśli zmienna jest zmienną właściwością, nie będziesz w stanie inteligentnie rzutować jej na jej typ, który nie dopuszcza wartości null w ifinstrukcji (ponieważ wartość mogła zostać zmodyfikowana przez inny wątek) i letzamiast tego musiałbyś użyć bezpiecznego operatora wywołania .

Bezpieczny operator połączeń ?.

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


Możesz go używać w połączeniu z operatorem Elvisa.

Operator Elvisa ?: (zgaduję, ponieważ znak przesłuchania wygląda jak włosy Elvisa)

a ?: println("null")

A jeśli chcesz uruchomić blok kodu

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

Połączenie tych dwóch

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
dlaczego nie używasz ifdo sprawdzania wartości zerowej? a?.let{} ?: run{}jest właściwe tylko w rzadkich przypadkach, w przeciwnym razie nie jest idiomatyczne
voddan

2
@voddan Nie sugerowałem, aby nie używać if do nullkontroli, wymieniłem inne możliwe opcje. Chociaż nie jestem pewien, czy runma jakiś rodzaj spadku wydajności. Zaktualizuję odpowiedź, aby była bardziej przejrzysta.
Benito Bertoli

1
@voddan Jeśli ajest a var, to korzystając z a?.let{} ?: run{}gwarancji, że zostanie on poprawnie powiązany w letcałym zakresie. Jeśli ajest val, to nie ma różnicy.
madeinqc

1
@madeinqc jeśli a jest a val, to użycie let jest inne i złe. Uważam, że ten artykuł jest bardzo dobry w wyjaśnianiu tego - Kotlin: Nie używaj LET tylko do sprawdzenia zerowego .
Sufian

39

Kotlin sposoby obsługi null

Bezpieczna operacja dostępu

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

Niech funkcjonuje

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

Wczesne wyjście

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

Niezmienne cienie

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
}

Domyślna wartość

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

Użyj val zamiast var

valjest tylko do odczytu, varjest zmienny. Zaleca się używanie jak największej liczby właściwości tylko do odczytu, są one bezpieczne dla wątków.

Użyj lateinit

Czasami nie można użyć niezmiennych właściwości. Na przykład dzieje się tak w systemie Android, gdy w onCreate()wywołaniu inicjowana jest jakaś właściwość . W takich sytuacjach Kotlin ma funkcję języka o nazwie 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()
}

Ostatnią z nich nazwałbym „wartością domyślną” (nie elvis), ponieważ 3/4 z nich używa elvisa.
AjahnCharles

@AjahnCharles ma sens))
Levon Petrosyan

1
to bzdura, każdy nowoczesny język radzi sobie lepiej z opcjami niż ten. to bardziej uciążliwy obowiązek niż korzyść dla programistów.
JBarros35

10

Dodatek do @Benito Bertoli,

kombinacja jest w rzeczywistości odmienna od if-else

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

Wynik to:

1. it=test

Ale jeśli:

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

Wynik to:

1. it=test
2. it is null!

Ponadto, jeśli najpierw użyjesz elvisa:

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

Wynik to:

1. it is null!
2. it=kotlin.Unit

5

Sprawdź przydatne metody, może się przydać:

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

Poniżej możliwy przykład wykorzystania tych funkcji:

var s: String? = null

// ...

if (s.isNotNullAndSatisfies{ isEmpty() }{
   // do something
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.