Pertama, Anda harus membaca semua tentang Null Safety di Kotlin yang mencakup kasus secara menyeluruh.
Di Kotlin, Anda tidak dapat mengakses nilai nullable tanpa yakin itu tidak null
( Memeriksa null dalam kondisi ), atau menyatakan bahwa itu pasti tidak null
menggunakan !!
operator yang pasti , mengaksesnya dengan ?.
Panggilan Aman , atau terakhir memberikan sesuatu yang mungkin null
merupakan nilai default menggunakan ?:
Operator Elvis .
Untuk kasus pertama Anda dalam pertanyaan, Anda memiliki opsi tergantung pada maksud kode yang akan Anda gunakan salah satunya, dan semuanya idiomatis tetapi memiliki hasil yang berbeda:
val something: Xyz? = createPossiblyNullXyz()
// access it as non-null asserting that with a sure call
val result1 = something!!.foo()
// access it only if it is not null using safe operator,
// returning null otherwise
val result2 = something?.foo()
// access it only if it is not null using safe operator,
// otherwise a default value using the elvis operator
val result3 = something?.foo() ?: differentValue
// null check it with `if` expression and then use the value,
// similar to result3 but for more complex cases harder to do in one expression
val result4 = if (something != null) {
something.foo()
} else {
...
differentValue
}
// null check it with `if` statement doing a different action
if (something != null) {
something.foo()
} else {
someOtherAction()
}
Untuk "Mengapa itu bekerja ketika null diperiksa" baca informasi latar belakang di bawah ini pada smart gips .
Untuk kasus ke-2 Anda dalam pertanyaan Anda dalam pertanyaan dengan Map
, jika Anda sebagai pengembang yakin hasilnya tidak pernah ada null
, gunakan !!
operator tertentu sebagai pernyataan:
val map = mapOf("a" to 65,"b" to 66,"c" to 67)
val something = map.get("a")!!
something.toLong() // now valid
atau dalam kasus lain, ketika peta BISA mengembalikan nol tetapi Anda dapat memberikan nilai default, maka Map
itu sendiri memiliki getOrElse
metode :
val map = mapOf("a" to 65,"b" to 66,"c" to 67)
val something = map.getOrElse("z") { 0 } // provide default value in lambda
something.toLong() // now valid
Informasi latar belakang:
Catatan: dalam contoh di bawah ini saya menggunakan tipe eksplisit untuk membuat perilaku jelas. Dengan inferensi tipe, biasanya tipe dapat dihilangkan untuk variabel lokal dan anggota pribadi.
Lebih lanjut tentang !!
operator pasti
The !!
Operator menegaskan bahwa nilai tersebut tidak null
atau melempar NPE. Ini harus digunakan dalam kasus di mana pengembang menjamin bahwa nilainya tidak akan pernah null
. Anggap saja sebagai penegasan diikuti oleh pemain cerdas .
val possibleXyz: Xyz? = ...
// assert it is not null, but if it is throw an exception:
val surelyXyz: Xyz = possibleXyz!!
// same thing but access members after the assertion is made:
possibleXyz!!.foo()
baca lebih lanjut: !! Tentu Operator
Lebih lanjut tentang null
Memeriksa dan Pemain Cerdas
Jika Anda melindungi akses ke tipe nullable dengan null
cek, kompiler akan dengan cerdas memasukkan nilai di dalam tubuh pernyataan menjadi non-nullable. Ada beberapa aliran rumit di mana ini tidak dapat terjadi, tetapi untuk kasus umum berfungsi dengan baik.
val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
// allowed to reference members:
possiblyXyz.foo()
// or also assign as non-nullable type:
val surelyXyz: Xyz = possibleXyz
}
Atau jika Anda melakukan is
pemeriksaan untuk jenis yang tidak dapat dibatalkan:
if (possibleXyz is Xyz) {
// allowed to reference members:
possiblyXyz.foo()
}
Dan hal yang sama untuk ekspresi 'kapan' yang juga aman dilemparkan:
when (possibleXyz) {
null -> doSomething()
else -> possibleXyz.foo()
}
// or
when (possibleXyz) {
is Xyz -> possibleXyz.foo()
is Alpha -> possibleXyz.dominate()
is Fish -> possibleXyz.swim()
}
Beberapa hal tidak memungkinkan null
pemeriksaan untuk pemeran cerdas untuk penggunaan variabel nanti. Contoh di atas menggunakan variabel lokal yang sama sekali tidak bisa bermutasi dalam aliran aplikasi, apakah val
atau var
variabel ini tidak punya kesempatan untuk bermutasi menjadi null
. Namun, dalam kasus lain di mana kompiler tidak dapat menjamin analisis aliran, ini akan menjadi kesalahan:
var nullableInt: Int? = ...
public fun foo() {
if (nullableInt != null) {
// Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
val nonNullableInt: Int = nullableInt
}
}
Siklus hidup variabel nullableInt
tidak sepenuhnya terlihat dan dapat ditugaskan dari utas lainnya, null
pemeriksaan tidak dapat dilakukan dengan cerdas ke nilai yang tidak dapat dibatalkan. Lihat topik "Panggilan Aman" di bawah ini untuk solusinya.
Kasus lain yang tidak dapat dipercaya oleh pemain cerdas untuk tidak bermutasi adalah val
properti pada objek yang memiliki pengambil kustom. Dalam hal ini, kompiler tidak memiliki visibilitas ke apa yang mengubah nilai dan oleh karena itu Anda akan mendapatkan pesan kesalahan:
class MyThing {
val possibleXyz: Xyz?
get() { ... }
}
// now when referencing this class...
val thing = MyThing()
if (thing.possibleXyz != null) {
// error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
thing.possiblyXyz.foo()
}
baca selengkapnya: Memeriksa null dalam kondisi
Lebih lanjut tentang ?.
operator Panggilan Aman
Operator panggilan aman mengembalikan nol jika nilai ke kiri adalah nol, jika tidak terus mengevaluasi ekspresi ke kanan.
val possibleXyz: Xyz? = makeMeSomethingButMaybeNullable()
// "answer" will be null if any step of the chain is null
val answer = possibleXyz?.foo()?.goo()?.boo()
Contoh lain di mana Anda ingin mengulang daftar tetapi hanya jika tidak null
dan tidak kosong, sekali lagi operator panggilan aman sangat berguna:
val things: List? = makeMeAListOrDont()
things?.forEach {
// this loops only if not null (due to safe call) nor empty (0 items loop 0 times):
}
Dalam salah satu contoh di atas kami memiliki kasus di mana kami melakukan if
pemeriksaan tetapi memiliki kesempatan utas lain bermutasi nilai dan karena itu tidak ada pemain pintar . Kami dapat mengubah sampel ini untuk menggunakan operator panggilan aman bersama dengan let
fungsi untuk menyelesaikan ini:
var possibleXyz: Xyz? = 1
public fun foo() {
possibleXyz?.let { value ->
// only called if not null, and the value is captured by the lambda
val surelyXyz: Xyz = value
}
}
baca selengkapnya: Panggilan Aman
Lebih lanjut tentang ?:
Operator Elvis
Operator Elvis memungkinkan Anda untuk memberikan nilai alternatif ketika ekspresi di sebelah kiri operator adalah null
:
val surelyXyz: Xyz = makeXyzOrNull() ?: DefaultXyz()
Ini memiliki beberapa kegunaan kreatif juga, misalnya melempar pengecualian ketika ada sesuatu null
:
val currentUser = session.user ?: throw Http401Error("Unauthorized")
atau untuk kembali lebih awal dari suatu fungsi:
fun foo(key: String): Int {
val startingCode: String = codes.findKey(key) ?: return 0
// ...
return endingValue
}
baca selengkapnya: Operator Elvis
Operator Null dengan Fungsi Terkait
Kotlin stdlib memiliki serangkaian fungsi yang bekerja sangat baik dengan operator yang disebutkan di atas. Sebagai contoh:
// use ?.let() to change a not null value, and ?: to provide a default
val something = possibleNull?.let { it.transform() } ?: defaultSomething
// use ?.apply() to operate further on a value that is not null
possibleNull?.apply {
func1()
func2()
}
// use .takeIf or .takeUnless to turn a value null if it meets a predicate
val something = name.takeIf { it.isNotBlank() } ?: defaultName
val something = name.takeUnless { it.isBlank() } ?: defaultName
Topik-topik terkait
Di Kotlin, sebagian besar aplikasi mencoba menghindari null
nilai, tetapi itu tidak selalu mungkin. Dan terkadang null
masuk akal. Beberapa pedoman untuk dipikirkan:
dalam beberapa kasus, ia menjamin jenis pengembalian yang berbeda yang mencakup status pemanggilan metode dan hasilnya jika berhasil. Perpustakaan seperti Hasil memberi Anda jenis hasil keberhasilan atau kegagalan yang juga dapat bercabang kode Anda. Dan perpustakaan Janji untuk Kotlin yang disebut Kovenan melakukan hal yang sama dalam bentuk janji.
untuk koleksi sebagai tipe pengembalian selalu mengembalikan koleksi kosong alih-alih null
, kecuali Anda memerlukan status ketiga "tidak ada". Kotlin memiliki fungsi pembantu seperti emptyList()
atauemptySet()
untuk membuat nilai-nilai kosong ini.
saat menggunakan metode yang mengembalikan nilai nullable yang Anda miliki default atau alternatif, gunakan operator Elvis untuk memberikan nilai default. Dalam hal Map
penggunaan getOrElse()
yang memungkinkan nilai default dihasilkan, bukan Map
metode get()
yang mengembalikan nilai nullable. Sama untukgetOrPut()
saat mengganti metode dari Java di mana Kotlin tidak yakin tentang nullability dari kode Java, Anda selalu dapat menghapus ?
nullability dari penggantian Anda jika Anda yakin apa tanda tangan dan fungsionalitasnya. Karena itu, metode yang Anda timpa lebih null
aman. Sama untuk mengimplementasikan antarmuka Java di Kotlin, ubah nullability menjadi apa yang Anda ketahui valid.
lihat fungsi yang sudah bisa membantu, seperti untuk String?.isNullOrEmpty()
dan String?.isNullOrBlank()
yang dapat beroperasi pada nilai yang dapat dibatalkan dengan aman dan melakukan apa yang Anda harapkan. Bahkan, Anda dapat menambahkan ekstensi Anda sendiri untuk mengisi celah di perpustakaan standar.
fungsi pernyataan seperti checkNotNull()
dan requireNotNull()
di perpustakaan standar.
fungsi pembantu seperti filterNotNull()
yang menghapus null dari koleksi, atau listOfNotNull()
untuk mengembalikan daftar nol atau item tunggal dari null
nilai yang mungkin .
ada operator cast Aman (nullable) juga yang memungkinkan pemain untuk non-nullable kembali nol jika tidak mungkin. Tapi saya tidak punya kasus penggunaan yang valid untuk ini yang tidak diselesaikan dengan metode lain yang disebutkan di atas.