apply adalah scope function yang menggunakan this sebagai receiver dan mengembalikan objek itu sendiri setelah block dijalankan. Pola ini sangat cocok untuk konfigurasi objek — kita mengubah beberapa property dalam satu block dan mendapatkan kembali objek yang sama untuk dipakai lebih lanjut. Pada chapter ini kita akan melihat empat pola apply — konfigurasi objek data class, builder pattern, konfigurasi collection, dan chaining dengan also.
Apa Itu apply #
Signature apply:
inline fun <T> T.apply(block: T.() -> Unit): T- Receiver: objek yang dipanggil
apply(tersedia sebagaithis). - Return: objek itu sendiri (
T). - Use case utama: konfigurasi objek.
Tabel Perbandingan apply dengan Scope Lain #
| Aspek | apply |
|---|---|
| Receiver | this (objek dipanggil apply) |
| Return | objek itu sendiri |
| Idiomatic use | Konfigurasi objek, builder pattern |
| Block return value | Diabaikan (Unit) |
Pola apply di Kode Nyata #
Mari kita lihat empat pola apply yang umum di kode Kotlin modern.
// apply_example.kt
// apply: receiver `this`, mengembalikan objek.
// Cocok untuk konfigurasi objek (builder pattern).
data class ServerConfig(
var host: String = "localhost",
var port: Int = 80,
var useHttps: Boolean = false,
var maxConnections: Int = 100,
var timeoutMs: Int = 5_000
)
class Server(private val config: ServerConfig) {
fun start() {
println("Server dimulai di ${config.host}:${config.port} " +
"(HTTPS=${config.useHttps}, max=${config.maxConnections})")
}
}
fun main() {
// Pola 1: konfigurasi objek dengan apply.
val config = ServerConfig().apply {
host = "127.0.0.1"
port = 8443
useHttps = true
maxConnections = 500
timeoutMs = 10_000
}
println("Config: $config")
// Pola 2: apply pada builder.
val server = Server(config).apply {
// Tidak ada property untuk diatur, tapi menunjukkan pattern.
start()
}
// Pola 3: apply pada collection.
val daftar = mutableListOf<String>().apply {
add("Belajar Kotlin")
add("Lambdas")
add("Scope functions")
}
println("Daftar: $daftar")
// Pola 4: apply dengan pengembalian objek untuk chaining.
val hasil = ServerConfig().apply {
host = "0.0.0.0"
port = 3000
}.also {
println(" Konfigurasi siap: ${it.host}:${it.port}")
}
println("Hasil akhir: ${hasil.host}:${hasil.port}")
}Output yang Dihasilkan:
Config: ServerConfig(host=127.0.0.1, port=8443, useHttps=true, maxConnections=500, timeoutMs=10000)
Server dimulai di 127.0.0.1:8443 (HTTPS=true, max=500)
Daftar: [Belajar Kotlin, Lambdas, Scope functions]
Konfigurasi siap: 0.0.0.0:3000
Hasil akhir: 0.0.0.0:3000Mari kita telaah baris-baris kode di atas:
- Baris 8-15 (
data class ServerConfigdengan beberapavarproperty): data class dengan property mutable. Kondisi ideal untukapply— kita akan mengatur beberapa property sekaligus. - Baris 17-23 (
class Server(private val config: ServerConfig)): class yang mengkonsumsiServerConfig. Methodstart()mencetak status. - Baris 27-34 (
val config = ServerConfig().apply { ... }): pola konfigurasi objek.ServerConfig()membuat instance dengan default.applymengikatthiske instance — kita mengubah lima property tanpa prefix. Block returnUnit(diabaikan),applymengembalikan instance yang sudah dikonfigurasi. Tanpaapply, kita menulisval config = ServerConfig(); config.host = ...; config.port = .... - Baris 37-40 (
val server = Server(config).apply { start() }): pola apply pada builder.applymengembalikanServersetelah block dijalankan. Block memanggilstart()sebagai bagian dari setup. - Baris 43-47 (
val daftar = mutableListOf<String>().apply { add(...); ... }): pola apply pada collection.mutableListOf<String>()membuat list kosong.applymemanggiladdbeberapa kali untuk mengisi list, lalu mengembalikan list yang sudah terisi. - Baris 50-55 (
val hasil = ServerConfig().apply { ... }.also { ... }): pola chaining apply + also.applymengonfigurasi dan mengembalikan objek, lalualsomelakukan side effect (log) tanpa mengubah alur. Hasil akhir adalah objekServerConfig.
apply untuk Builder Pattern #
apply sangat populer untuk builder pattern — membuat instance dan mengonfigurasinya dalam satu ekspresi. Pola ini menggantikan boilerplate constructor yang panjang atau setter berantai di Java.
val config = ServerConfig().apply {
host = "0.0.0.0"
port = 8080
useHttps = true
}
// Ekspresi tunggal — instance dibuat, dikonfigurasi, dan diassignTanpa apply:
val config = ServerConfig()
config.host = "0.0.0.0"
config.port = 8080
config.useHttps = trueapply pada Android dan UI Framework #
apply sangat populer di Android untuk konfigurasi View dan intent:
val intent = Intent(context, TargetActivity::class.java).apply {
putExtra("id", 42)
putExtra("nama", "Budi")
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}Kapan apply vs Constructor Default #
apply cocok bila property bersifat opsional atau bila kita ingin menimpa beberapa default. Bila semua property wajib dan tidak ada default, gunakan constructor biasa dengan parameter lengkap — lebih aman karena kompilator memaksa penyediaan semua argumen.
Referensi Lanjutan #
- Scope functions
— panduan resmi
applyuntuk konfigurasi objek - Higher-order functions and lambdas
— dasar lambda receiver pada
apply
Penutup #
apply adalah scope function paling populer untuk konfigurasi objek. Dengan this sebagai receiver dan kembalian objek itu sendiri, apply menggantikan pola setter berantai dan membuat kode terbaca seperti blok konfigurasi. Pola ini sangat berguna untuk builder, koleksi mutable, dan objek konfigurasi. Selanjutnya, kita akan mempelajari also — scope function yang juga mengembalikan objek tetapi memakai it dan cocok untuk side effect tanpa mengganggu chain.