Kotlin adalah bahasa pemrograman banyak digunakan oleh pengembang Android di mana saja. Topik ini berfungsi sebagai kursus kilat Kotlin yang dapat membantu Anda bekerja dengan cepat.
Deklarasi variabel
Kotlin menggunakan dua kata kunci yang berbeda untuk mendeklarasikan variabel: val
dan var
.
- Gunakan
val
untuk variabel yang nilainya tidak pernah berubah. Anda tidak dapat menetapkan ulang nilai ke variabel yang dideklarasikan menggunakanval
. - Gunakan
var
untuk variabel yang nilainya dapat berubah.
Pada contoh di bawah, count
adalah variabel dari jenis Int
yang diberi
nilai awal 10
:
var count: Int = 10
Int
adalah jenis yang merepresentasikan bilangan bulat, salah satu dari berbagai jenis numerik yang
dapat direpresentasikan di Kotlin. Serupa dengan bahasa lain, Anda juga dapat menggunakan
Byte
, Short
, Long
, Float
, dan Double
, bergantung pada data numerik Anda.
Kata kunci var
berarti Anda dapat menetapkan ulang nilai ke count
sesuai kebutuhan. Misalnya,
Anda dapat mengubah nilai count
dari 10
menjadi 15
:
var count: Int = 10
count = 15
Namun, beberapa nilai tidak dapat diubah. Pertimbangkan String
yang disebut
languageName
. Jika ingin memastikan bahwa languageName
selalu memiliki nilai
"Kotlin", Anda dapat mendeklarasikan languageName
menggunakan kata kunci val
:
val languageName: String = "Kotlin"
Kata kunci ini memungkinkan Anda untuk menjelaskan apa saja yang dapat diubah. Gunakan untuk
keuntungan Anda sesuai kebutuhan. Jika referensi variabel harus ditetapkan ulang,
deklarasikan sebagai var
. Jika tidak, gunakan val
.
Inferensi jenis
Melanjutkan contoh sebelumnya, saat Anda menetapkan nilai awal ke
languageName
, compiler Kotlin dapat menganggap jenis berdasarkan jenis
nilai yang ditetapkan.
Karena nilai "Kotlin"
adalah dari jenis String
, compiler menganggap bahwa
languageName
juga merupakan String
. Perhatikan bahwa Kotlin adalah bahasa berjenis statis.
Ini berarti bahwa jenis ini diselesaikan pada waktu kompilasi dan tidak pernah
berubah.
Pada contoh berikut, languageName
dianggap sebagai String
, sehingga Anda tidak dapat
memanggil fungsi apa pun yang bukan bagian dari class String
:
val languageName = "Kotlin"
val upperCaseName = languageName.toUpperCase()
// Fails to compile
languageName.inc()
toUpperCase()
adalah fungsi yang hanya dapat dipanggil pada variabel jenis
String
. Karena compiler Kotlin telah menganggap languageName
sebagai String
,
Anda dapat memanggil toUpperCase()
dengan aman. Akan tetapi, inc()
adalah fungsi operator
Int
, sehingga tidak dapat dipanggil di String
. Pendekatan Kotlin untuk inferensi jenis
memberi Anda keringkasan dan keamanan jenis.
Keamanan null
Dalam beberapa bahasa, variabel jenis referensi dapat dideklarasikan tanpa memberikan nilai eksplisit awal. Dalam kasus ini, variabel biasanya berisi nilai null. Secara default, variabel Kotlin tidak dapat memiliki nilai null. Artinya, cuplikan berikut tidak valid:
// Fails to compile
val languageName: String = null
Untuk variabel yang memiliki nilai null, jenisnya harus nullable. Anda dapat
menentukan variabel sebagai nullable dengan menambahkan akhiran jenisnya dengan ?
, seperti yang ditunjukkan
dalam contoh berikut:
val languageName: String? = null
Dengan jenis String?
, Anda dapat menetapkan nilai String
atau null
ke
languageName
.
Anda harus menangani variabel nullable dengan hati-hati atau akan timbul risiko
NullPointerException
yang dikhawatirkan. Di Java, misalnya, jika Anda mencoba memanggil metode
pada nilai null, program akan error.
Kotlin menyediakan sejumlah mekanisme untuk bekerja secara aman dengan variabel nullable. Untuk informasi selengkapnya, lihat Pola Kotlin umum di Android: Nullability.
Bersyarat
Kotlin memiliki beberapa mekanisme untuk menerapkan logika bersyarat. Yang paling
umum adalah pernyataan if-else. Jika ekspresi yang digabungkan dalam
tanda kurung di samping kata kunci if
mengevaluasi ke true
, kode dalam
cabang tersebut (yaitu, kode yang langsung diikuti dan digabungkan dengan tanda kurung
kurawal) akan dieksekusi. Jika tidak, kode dalam cabang else
yang akan dieksekusi.
if (count == 42) {
println("I have the answer.")
} else {
println("The answer eludes me.")
}
Anda dapat merepresentasikan beberapa kondisi menggunakan else if
. Hal ini memungkinkan Anda merepresentasikan
logika yang lebih terperinci dan kompleks dalam pernyataan bersyarat tunggal, seperti yang ditunjukkan dalam contoh berikut:
if (count == 42) {
println("I have the answer.")
} else if (count > 35) {
println("The answer is close.")
} else {
println("The answer eludes me.")
}
Pernyataan bersyarat berguna untuk merepresentasikan logika berstatus, tetapi Anda mungkin
mendapati bahwa Anda melakukan pengulangan sendiri saat menulisnya. Pada contoh di atas, Anda
cukup mencetak String
di setiap cabang. Untuk menghindari pengulangan ini, Kotlin menawarkan
ekspresi bersyarat. Contoh terakhir dapat ditulis ulang sebagai berikut:
val answerString: String = if (count == 42) {
"I have the answer."
} else if (count > 35) {
"The answer is close."
} else {
"The answer eludes me."
}
println(answerString)
Secara implisit, setiap cabang bersyarat menampilkan hasil ekspresi pada
baris terakhirnya, sehingga Anda tidak perlu menggunakan kata kunci return
. Karena hasil dari
ketiga cabang berjenis String
, hasil dari ekspresi if-else
juga berjenis String
. Dalam contoh ini, answerString
diberi nilai awal
dari hasil ekspresi if-else. Inferensi jenis dapat digunakan untuk
menghapus deklarasi jenis eksplisit untuk answerString
, tetapi sebaiknya
sertakan deklarasi tersebut untuk kejelasan.
Dengan semakin kompleksnya pernyataan bersyarat, Anda dapat mempertimbangkan untuk mengganti ekspresi if-else dengan ekspresi when, seperti yang ditunjukkan dalam contoh berikut:
val answerString = when {
count == 42 -> "I have the answer."
count > 35 -> "The answer is close."
else -> "The answer eludes me."
}
println(answerString)
Setiap cabang dalam ekspresi when
direpresentasikan oleh suatu kondisi, tanda panah
(->
), dan hasilnya. Jika kondisi di sisi kiri tanda panah
mengevaluasi ke true, maka hasil ekspresi di sisi kanan akan
ditampilkan. Perhatikan bahwa eksekusi tidak jatuh dari satu cabang ke cabang berikutnya.
Kode dalam contoh ekspresi when
secara fungsional setara dengan contoh ekspresi dalam
contoh sebelumnya, tetapi boleh dibilang lebih mudah dibaca.
Persyaratan Kotlin menyoroti salah satu fiturnya yang lebih canggih, yaitu transmisi cerdas. Daripada menggunakan operator panggilan aman atau operator pernyataan not-null agar berfungsi dengan nilai nullable, Anda dapat memeriksa apakah sebuah variabel berisi referensi ke nilai null menggunakan pernyataan bersyarat, seperti yang ditunjukkan dalam contoh berikut:
val languageName: String? = null
if (languageName != null) {
// No need to write languageName?.toUpperCase()
println(languageName.toUpperCase())
}
Dalam cabang bersyarat, languageName
dapat dianggap sebagai non-nullable.
Kotlin cukup cerdas untuk mengetahui bahwa kondisi untuk menjalankan cabang
adalah karena languageName
tidak berisi nilai null, sehingga Anda tidak perlu memperlakukan
languageName
sebagai nullable dalam cabang tersebut. Transmisi cerdas ini berfungsi untuk pemeriksaan null,
pemeriksaan jenis,
atau kondisi apa pun yang memenuhi
kontrak.
Fungsi
Anda dapat mengelompokkan satu atau beberapa ekspresi menjadi fungsi. Daripada mengulangi rangkaian ekspresi yang sama setiap kali membutuhkan hasil, Anda dapat menggabungkan ekspresi dalam fungsi dan memanggil fungsi tersebut.
Untuk mendeklarasikan fungsi, gunakan kata kunci fun
diikuti dengan nama fungsi.
Selanjutnya, tentukan jenis input yang digunakan oleh fungsi Anda, jika ada, dan deklarasikan
jenis output yang dihasilkannya. Isi fungsi adalah tempat Anda menetapkan
ekspresi yang dipanggil saat fungsi Anda dipanggil.
Berdasarkan contoh sebelumnya, berikut adalah fungsi Kotlin yang lengkap:
fun generateAnswerString(): String {
val answerString = if (count == 42) {
"I have the answer."
} else {
"The answer eludes me"
}
return answerString
}
Fungsi dalam contoh di atas memiliki nama generateAnswerString
. Tidak
perlu input apa pun. Ini menghasilkan hasil dari jenis String
. Untuk memanggil
fungsi, gunakan namanya, diikuti oleh operator panggilan (()
). Pada
contoh di bawah, variabel answerString
diinisialisasi dengan hasil dari
generateAnswerString()
.
val answerString = generateAnswerString()
Fungsi dapat mengambil argumen sebagai input, seperti yang ditunjukkan pada contoh berikut:
fun generateAnswerString(countThreshold: Int): String {
val answerString = if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
return answerString
}
Saat mendeklarasikan fungsi, Anda dapat menentukan berapa pun jumlah argumen dan
jenisnya. Pada contoh di atas, generateAnswerString()
mengambil satu argumen yang bernama
countThreshold
dari jenis Int
. Dalam fungsi, Anda dapat merujuk ke
argumen menggunakan namanya.
Saat memanggil fungsi ini, Anda harus menyertakan argumen dalam tanda kurung panggilan fungsi:
val answerString = generateAnswerString(42)
Menyederhanakan deklarasi fungsi
generateAnswerString()
adalah fungsi yang cukup sederhana. Fungsi tersebut mendeklarasikan
variabel, dan langsung menampilkan hasil. Jika hasil ekspresi tunggal
ditampilkan dari fungsi, Anda dapat melewati deklarasi variabel lokal dengan langsung
menampilkan hasil ekspresi if-else yang terdapat dalam fungsi, seperti
yang ditunjukkan dalam contoh berikut:
fun generateAnswerString(countThreshold: Int): String {
return if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
}
Anda juga dapat mengganti kata kunci kembali dengan operator penugasan:
fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
"I have the answer"
} else {
"The answer eludes me"
}
Fungsi anonim
Tidak semua fungsi memerlukan nama. Beberapa fungsi lebih teridentifikasi secara langsung berdasarkan input dan outputnya. Fungsi ini disebut fungsi anonim. Anda dapat menyimpan referensi ke fungsi anonim, menggunakan referensi ini untuk memanggil fungsi anonim nanti. Anda juga dapat meneruskan referensi di sekitar aplikasi, seperti jenis referensi lainnya.
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
Seperti fungsi bernama, fungsi anonim dapat berisi sejumlah ekspresi. Nilai dari fungsi yang ditampilkan adalah hasil ekspresi akhir.
Pada contoh di atas, stringLengthFunc
berisi referensi ke fungsi anonim
yang mengambil file String
sebagai input dan menampilkan panjang input
String
sebagai output dari jenis Int
. Karena itu, jenis fungsi
dinyatakan sebagai (String) -> Int
. Akan tetapi, kode ini tidak menjalankan fungsinya.
Untuk mengambil hasil fungsi, Anda harus memanggilnya seperti
fungsi bernama. Anda harus memberikan String
saat memanggil stringLengthFunc
, seperti
yang ditunjukkan d alam contoh berikut:
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
val stringLength: Int = stringLengthFunc("Android")
Fungsi urutan yang lebih tinggi
Fungsi dapat mengambil fungsi lain sebagai argumen. Fungsi yang menggunakan fungsi lain sebagai argumen disebut fungsi urutan yang lebih tinggi. Pola ini berguna untuk melakukan komunikasi antar komponen dengan cara yang sama seperti saat Anda menggunakan antarmuka callback di Java.
Berikut adalah contoh fungsi urutan yang lebih tinggi:
fun stringMapper(str: String, mapper: (String) -> Int): Int {
// Invoke function
return mapper(str)
}
Fungsi stringMapper()
mengambil String
bersama dengan fungsi yang
memperoleh nilai Int
dari String
yang Anda teruskan ke dalamnya.
Anda dapat memanggil stringMapper()
dengan meneruskan String
dan fungsi yang
memenuhi parameter input lainnya, yaitu fungsi yang mengambil String
sebagai
input dan output Int
, seperti yang ditunjukkan dalam contoh berikut:
stringMapper("Android", { input ->
input.length
})
Jika fungsi anonim adalah parameter last yang didefinisikan pada fungsi, Anda dapat meneruskannya di luar tanda kurung yang digunakan untuk memanggil fungsi, seperti yang ditunjukkan dalam contoh berikut:
stringMapper("Android") { input ->
input.length
}
Fungsi anonim dapat ditemukan di seluruh library standar Kotlin. Untuk informasi selengkapnya, lihat Fungsi Urutan yang Lebih Tinggi dan Lambda.
Class
Semua jenis yang disebutkan sejauh ini di-build ke dalam bahasa pemrograman
Kotlin. Jika ingin menambahkan jenis kustom Anda sendiri, tentukan class
menggunakan kata kunci class
, seperti yang ditunjukkan dalam contoh berikut:
class Car
Properti
Class merepresentasikan status menggunakan properti.
Properti adalah
variabel tingkat class yang dapat menyertakan pengambil, penyetel, dan kolom dukungan.
Karena mobil memerlukan roda untuk berjalan, Anda dapat menambahkan daftar objek Wheel
sebagai
properti Car
, seperti yang ditunjukkan dalam contoh berikut:
class Car {
val wheels = listOf<Wheel>()
}
Perhatikan bahwa wheels
adalah public val
, artinya wheels
dapat diakses dari
luar class Car
, dan tidak dapat ditetapkan ulang. Jika ingin mendapatkan
instance dari Car
, Anda harus terlebih dahulu memanggil konstruktornya. Dari sana, Anda dapat
mengakses semua properti yang dapat diakses.
val car = Car() // construct a Car
val wheels = car.wheels // retrieve the wheels value from the Car
Jika ingin menyesuaikan roda, Anda dapat menentukan konstruktor kustom yang menentukan cara properti class Anda diinisialisasi:
class Car(val wheels: List<Wheel>)
Pada contoh di atas, konstruktor class mengambil List<Wheel>
sebagai
argumen konstruktor dan menggunakan argumen tersebut untuk menginisialisasi properti wheels
miliknya.
Fungsi dan enkapsulasi class
Class menggunakan fungsi untuk memodelkan perilaku. Fungsi dapat mengubah status, sehingga membantu Anda menampilkan data yang hanya ingin Anda ungkap. Kontrol akses ini adalah bagian dari konsep berorientasi objek yang lebih besar yang dikenal sebagai enkapsulasi.
Pada contoh berikut, properti doorLock
bersifat pribadi dari apa pun
di luar class Car
. Untuk membuka kunci mobil, Anda harus memanggil fungsi unlockDoor()
yang meneruskan dengan kunci yang valid, seperti yang ditunjukkan dalam contoh berikut:
class Car(val wheels: List<Wheel>) {
private val doorLock: DoorLock = ...
fun unlockDoor(key: Key): Boolean {
// Return true if key is valid for door lock, false otherwise
}
}
Jika Anda ingin menyesuaikan cara properti direferensikan, Anda dapat memberikan
pengambil dan penyetel kustom. Misalnya, jika Anda ingin menampilkan pengambil properti
sekaligus membatasi akses ke penyetelnya, Anda dapat menetapkan penyetel tersebut sebagai
private
:
class Car(val wheels: List<Wheel>) {
private val doorLock: DoorLock = ...
var gallonsOfFuelInTank: Int = 15
private set
fun unlockDoor(key: Key): Boolean {
// Return true if key is valid for door lock, false otherwise
}
}
Dengan kombinasi properti dan fungsi, Anda dapat membuat class yang memodelkan semua jenis objek.
Interoperabilitas
Salah satu fitur terpenting Kotlin adalah interoperabilitas yang dapat disesuaikannya dengan Java. Karena kode Kotlin mengompilasi ke JVM bytecode, kode Kotlin Anda dapat memanggil langsung ke kode Java dan sebaliknya. Ini berarti Anda dapat memanfaatkan library Java yang sudah ada langsung dari Kotlin. Selain itu, sebagian besar Android API juga ditulis dalam Java, dan Anda dapat memanggilnya langsung dari Kotlin.
Langkah berikutnya
Kotlin adalah bahasa yang fleksibel dan pragmatis dengan dukungan dan momentum yang terus berkembang. Jika Anda belum mencobanya, lakukan sekarang. Untuk langkah selanjutnya, lihat di dokumentasi Kotlin resmi beserta panduan tentang cara mengajukan pola Kotlin umum di aplikasi Android Anda.