Skip to main content

Higher-Order Functions

Higher-Order Function adalah function yang dapat:

  1. Menerima function lain sebagai parameter.
  2. Mengembalikan function lain sebagai return value.

Higher-Order Function sangat berguna ketika kita ingin membuat function yang bersifat general dan fleksibel.

Dengan Higher-Order Function, kita dapat menentukan perilaku tertentu ketika function dipanggil dengan mengirimkan lambda expression sebagai argument.

Function sebagai Parameter​

Contoh sederhana Higher-Order Function:

fun hello(
name: String,
sayHello: (String) -> String
): String {
return "Halo ${sayHello(name)}"
}

Function hello() memiliki dua parameter:

name: String

dan:

sayHello: (String) -> String

Parameter sayHello merupakan function type.

Artinya, sayHello dapat menerima sebuah function yang:

  • Menerima satu parameter String.
  • Mengembalikan String.

Secara sederhana:

name
↓
String

sayHello
↓
(String) → String

Memanggil Higher-Order Function​

Kita dapat membuat lambda terlebih dahulu:

val upper = { value: String ->
value.uppercase()
}

Lambda tersebut menerima String dan mengubahnya menjadi huruf besar.

Kemudian lambda dikirimkan ke function hello():

println(hello("Ucup", upper))

Prosesnya:

"Ucup"
↓
upper()
↓
"UCUP"
↓
"Halo UCUP"

Output:

Halo UCUP

Contoh Menggunakan Lambda Langsung​

Lambda juga dapat langsung diberikan ketika memanggil function.

Contoh:

println(
hello(
"Budi",
{ value: String ->
value.lowercase()
}
)
)

Output:

Halo budi

Pada contoh tersebut, kita tidak perlu membuat variable lambda terlebih dahulu.

Lambda langsung diberikan sebagai argument ke function hello().

Type Inference pada Lambda​

Kita juga dapat menghilangkan tipe parameter jika Kotlin sudah dapat mengetahuinya dari function type.

Contoh:

println(
hello(
"Asep",
{ value ->
value.lowercase()
}
)
)

Kotlin mengetahui bahwa:

value

bertipe String karena parameter sayHello memiliki function type:

(String) -> String

Contoh Program Lengkap​

fun main() {

fun hello(
name: String,
sayHello: (String) -> String
): String {
return "Halo ${sayHello(name)}"
}

val upper = { value: String ->
value.uppercase()
}

println(hello("Ucup", upper))

println(
hello(
"Budi",
{ value: String ->
value.lowercase()
}
)
)

println(
hello(
"Asep",
{ value ->
value.lowercase()
}
)
)
}

Output:

Halo UCUP
Halo budi
Halo asep

Trailing Lambda​

Kotlin memiliki fitur bernama Trailing Lambda.

Trailing Lambda memungkinkan lambda expression diletakkan di luar tanda kurung pemanggilan function jika lambda tersebut merupakan argument terakhir.

Contoh tanpa trailing lambda:

val upper = hello(
"Ucup",
{ value: String ->
value.uppercase()
}
)

Karena parameter lambda berada di posisi terakhir, kita dapat menuliskannya sebagai:

val upper = hello("Ucup") { value: String ->
value.uppercase()
}

Kedua kode tersebut memiliki hasil yang sama.

Mengapa Menggunakan Trailing Lambda?​

Trailing Lambda membuat kode lebih ringkas dan mudah dibaca.

Tanpa trailing lambda:

hello(
"Ucup",
{ value: String ->
value.uppercase()
}
)

Dengan trailing lambda:

hello("Ucup") { value: String ->
value.uppercase()
}

Kotlin akan menganggap lambda tersebut sebagai argument terakhir dari function.

Function dengan Lambda Tanpa Parameter​

Higher-Order Function juga dapat menerima lambda yang tidak memiliki parameter.

Contohnya:

fun sayMessage(message: () -> String): String {
return "The Message ${message()}"
}

Perhatikan function type:

() -> String

Artinya:

() → tidak memiliki parameter
-> String → mengembalikan String

Jadi function message menerima lambda yang:

  • Tidak memiliki parameter.
  • Menghasilkan String.

Memanggil Function dengan Lambda​

Kita dapat memanggil function tersebut menggunakan sintaks biasa:

val theMessage = sayMessage({
"Good Luck My Friends"
})

println(theMessage)

Output:

The Message Good Luck My Friends

Lambda:

{
"Good Luck My Friends"
}

tidak menerima parameter dan menghasilkan String.

Menggunakan Trailing Lambda​

Karena lambda merupakan parameter terakhir, kita dapat menggunakan trailing lambda.

Contoh:

println(
sayMessage {
"Good Luck My Friends"
}
)

Kode tersebut lebih ringkas dibandingkan:

println(
sayMessage({
"Good Luck My Friends"
})
)

Keduanya menghasilkan output yang sama:

The Message Good Luck My Friends

Contoh Program Trailing Lambda​

fun main() {

fun sayMessage(message: () -> String): String {
return "The Message ${message()}"
}

// Sintaks normal
val theMessage = sayMessage({
"Good Luck My Friends"
})

println(theMessage)

// Trailing lambda
println(
sayMessage {
"Good Luck My Friends"
}
)
}

Output:

The Message Good Luck My Friends
The Message Good Luck My Friends

Perbandingan Sintaks Normal dan Trailing Lambda​

Sintaks Normal​

sayMessage({
"Good Luck My Friends"
})

Lambda berada di dalam tanda kurung.

Trailing Lambda​

sayMessage {
"Good Luck My Friends"
}

Lambda diletakkan di luar tanda kurung karena lambda merupakan argument terakhir.

Higher-Order Function dengan Dua Lambda​

Sebuah Higher-Order Function juga dapat menerima lebih dari satu function sebagai parameter.

Contoh:

fun calculate(
value: Int,
operation: (Int) -> Int
): Int {
return operation(value)
}

Function tersebut menerima:

value
↓
Int

operation
↓
(Int) → Int

Pemanggilan:

val result = calculate(10) {
it * 5
}

println(result)

Output:

50

Lambda:

{
it * 5
}

bertugas menentukan operasi yang dilakukan terhadap nilai 10.

Membuat Function yang Fleksibel​

Salah satu keuntungan Higher-Order Function adalah kita dapat membuat satu function yang memiliki perilaku berbeda berdasarkan lambda yang diberikan.

Contoh:

fun calculate(
value: Int,
operation: (Int) -> Int
): Int {
return operation(value)
}

Kita dapat melakukan perkalian:

println(
calculate(10) {
it * 5
}
)

Output:

50

Kita juga dapat melakukan penjumlahan:

println(
calculate(10) {
it + 20
}
)

Output:

30

Atau melakukan pengurangan:

println(
calculate(10) {
it - 3
}
)

Output:

7

Function calculate() tetap sama.

Yang berbeda adalah lambda yang dikirimkan sebagai parameter.

Higher-Order Function Mengembalikan Function​

Higher-Order Function tidak hanya dapat menerima function sebagai parameter.

Function juga dapat mengembalikan function.

Contoh:

fun createMultiplier(value: Int): (Int) -> Int {
return { number ->
number * value
}
}

Function tersebut mengembalikan:

(Int) -> Int

Artinya hasil dari createMultiplier() adalah sebuah function yang menerima Int dan menghasilkan Int.

Penggunaan:

val kaliLima = createMultiplier(5)

println(kaliLima(10))

Output:

50

Prosesnya:

createMultiplier(5)
↓
menghasilkan
↓
(Int) -> Int
↓
kaliLima(10)
↓
50

Contoh Program Lengkap​

Berikut contoh Higher-Order Function yang menerima dan mengembalikan function:

fun createMultiplier(value: Int): (Int) -> Int {
return { number ->
number * value
}
}

fun main() {

val kaliLima = createMultiplier(5)

println(kaliLima(10))

val kaliSepuluh = createMultiplier(10)

println(kaliSepuluh(10))
}

Output:

50
100

Kapan Menggunakan Higher-Order Function?​

Higher-Order Function cocok digunakan ketika kita ingin membuat function yang fleksibel dan perilakunya dapat ditentukan oleh pemanggil.

Contohnya:

  • Membuat function yang dapat menerima berbagai operasi.
  • Membuat filter data.
  • Membuat transformasi data.
  • Membuat callback.
  • Memproses collection.
  • Membuat kode yang reusable.
  • Membuat API function yang fleksibel.

Contoh sederhana:

fun process(
value: String,
action: (String) -> String
): String {
return action(value)
}

Pemanggil dapat menentukan sendiri apa yang dilakukan terhadap value.

Kesimpulan​

Higher-Order Function adalah function yang:

  1. Menerima function lain sebagai parameter.
  2. Mengembalikan function lain sebagai return value.
  3. Bisa melakukan keduanya.

Contoh menerima function sebagai parameter:

fun hello(
name: String,
sayHello: (String) -> String
): String {
return "Halo ${sayHello(name)}"
}

Contoh penggunaannya:

println(
hello("Ucup") {
it.uppercase()
}
)

Output:

Halo UCUP

Higher-Order Function juga mendukung Trailing Lambda:

sayMessage {
"Good Luck My Friends"
}

Jika lambda merupakan argument terakhir, Kotlin memungkinkan kita meletakkannya di luar tanda kurung.

Selain menerima function, Higher-Order Function juga dapat mengembalikan function:

fun createMultiplier(value: Int): (Int) -> Int {
return { number ->
number * value
}
}

Konsep utamanya:

tip

Higher-Order Function memungkinkan function menerima atau mengembalikan function lain sehingga kode menjadi lebih fleksibel, reusable, dan dapat disesuaikan dengan kebutuhan pemanggilnya.