1. Code
  2. Coding Fundamentals

Kotlin dari Dasar: Packages dan Function Dasar

Kotlin adalah bahasa pemrograman modern yang mengkompilasi ke Java bytecode. Ini gratis dan open source, dan menjanjikan untuk membuat coding untuk Android semakin menyenangkan. 
Scroll to top
This post is part of a series called Kotlin From Scratch.
Kotlin From Scratch: Ranges and Collections
Kotlin From Scratch: More Fun With Functions

Indonesian (Bahasa Indonesia) translation by Imam Firmansyah (you can also view the original English article)

Kotlin adalah bahasa pemrograman modern yang mengkompilasi ke Java bytecode. Ini gratis dan open source, dan menjanjikan untuk membuat coding untuk Android semakin menyenangkan. 

Pada artikel sebelumnya, Anda belajar tentang ranges dan collections di Kotlin. Dalam tutorial ini, kita akan belajar bahasa dengan melihat bagaimana mengatur kode menggunakan packages, dan kemudian melanjutkan pengenalan function di Kotlin.

1. Packages

Jika Anda sudah familiar dengan Java, Anda tahu Java menggunakan packages untuk mengelompokkan class terkait; Sebagai contoh, packages java.util memiliki sejumlah class utilitas. Packages dideklarasikan dengan kata kunci package, dan file Kotlin dengan deklarasi package di awal dapat berisi deklarasi class, function, atau interface. 

Deklarasi

Lihatlah kode di bawah ini, kami telah mendeklarasikan package com.chikekotlin.projectx menggunakan kata kunci package. Kami juga mendeklarasikan class MyClass (kami akan membahas class di Kotlin di artikel selanjutnya) di dalam package ini.

1
package com.chikekotlin.projectx
2
3
class MyClass

Sekarang, nama yang memenuhi syarat untuk class MyClass adalah com.chikekotlin.projectx.MyClass.

1
package com.chikekotlin.projectx
2
3
fun saySomething(): String {
4
    return "How far?"
5
}

Pada kode di atas, top-level function telah dibuat (kita akan segera melakukannya). Begitu juga dengan MyClass, nama yang memenuhi syarat untuk function saySomething() adalah com.chikekotlin.projectx.saySomething.

Import

Di Kotlin, kami menggunakan deklarasi import untuk mengaktifkan compiler untuk menemukan class, function, interface atau object yang akan diimpor. Di sisi lain, pada Java kita tidak dapat secara langsung mengimpor function atau class hanya method atau interface.

Kami menggunakan import untuk mengakses function, interface, class atau object di luar package tempat dideklarasikan.

1
import com.chikekotlin.projectx.saySomething
2
3
fun main(args: Array<String>) {
4
    saySomething() // will print "How far?"

5
}

Dalam potongan kode di atas, kita mengimpor function saySomething() dari package yang berbeda, dan kemudian kita menjalankan function tersebut. 

Kotlin juga mendukung impor wildcard menggunakan operator *. Operator akan mengimpor semua class, interface dan function yang dideklarasikan dalam package secara sekaligus. Hal ini tidak disarankan, meskipun-biasanya lebih baik membuat impor Anda eksplisit.

1
import com.chikekotlin.projectx.*

Import Aliasing

Bila Anda memiliki perpustakaan yang memiliki nama kelas atau function yang bertentangan (misalnya masing-masing mendeklarasikan function dengan nama yang sama), Anda dapat menggunakan kata kunci as untuk diberikan ke entitas yang diimpor tersebut sebagai nama sementara. 

1
import com.chikekotlin.projectx.saySomething
2
import com.chikekotlin.projecty.saySomething as projectYSaySomething
3
4
fun main(args: Array<String>) {
5
    projectYSaySomething() 
6
}

Perhatikan bahwa nama sementara hanya digunakan di dalam file yang telah ditetapkan.

2. Functions

Sebuah kelompok function dan serangkaian pernyataan kode yang melakukan tugas. Rincian pelaksanaan function disembunyikan dari pemanggil. 

Di Kotlin, function didefinisikan dengan menggunakan kata kunci fun, seperti yang ditunjukkan pada contoh berikut:

1
fun hello(name: String): String {
2
    return "Hello $name"
3
}
4
val message = hello("Chike")
5
print(message) // will print "Hello Chike"

Pada kode yang berada di atas, kita mendefinisikan sebuah function sederhana hello() dengan satu parameter tunggal name dengan tipe String. Function ini mengembalikan tipe String. The parameter definition format for functions is name: type, e.g. age: Intprice: Doublestudent: StudentClass.

1
fun hello(name: String): Unit {
2
   print("Hello $name")
3
}
4
5
hello("Chike") // will print "Hello Chike"

Function diatas hampir mirip dengan yang sebelumnya, tapi perhatikan bahwa yang satu ini memiliki tipe pengembalian Unit. Karena function ini tidak mengembalikan satupun nilai signifikan - hanya menampilkan pesan - secara default tipe pengembaliannya adalah Unit. Unit adalah sebuah object di Kotlin (kita akan membahas object Kotlin di artikel selanjutnya) yang mirip dengan tipe Void pada Java dan C. 

1
public object Unit {
2
    override fun toString() = "kotlin.Unit"
3
}

Perhatikan bahwa jika Anda tidak secara eksplisit menyatakan tipe pengembalian menjadi Unit, jenisnya akan disimpulkan oleh compiler. 

1
fun hello(name: String) { // will still compile

2
   print("Hello $name")
3
}

Single-Line Functions

Single-line atau one-line functions adalah function yang hanya memiliki sati ekspresi. Pada function ini kita akan mendapatkan In this function, kita menyingkirkan kurung kurawal dan menggunakan simbol = sebelum ekspresi. Dengan kata lain, kita menyingkirkan blok function. 

1
fun calCircumference(radius: Double): Double {
2
    return (2 * Math.PI) * radius
3
}

Function diatas bisa dipersingkat menjadi satu baris:

1
fun calCircumference(radius: Double) = (2 * Math.PI) * radius

Lihatlah function yang diperbarui di atas, Anda dapat melihat bahwa kami telah membuat kode menjadi lebih singkat dengan menghapus kurung kurawal {}, kata kunci return, dan juga jenis pengembalian (yang disimpulkan oleh compiler).

Anda masih bisa memasukkan tipe pengembalian agar lebih eksplisit. 

1
fun calCircumference(radius: Double): Double = (2 * Math.PI) * radius

Named Parameters

Parameter yang diberi nama memungkinkan function lebih mudah dibaca dengan memberi nama parameter yang dilewatkan ke function saat dipanggil. 

Pada contoh berikut, kami membuat sebuah function yang mencetak nama lengkap.

1
fun sayMyFullName(firstName: String, lastName: String, middleName: String): Unit {
2
    print("My full name is $firstName $middleName $lastName");
3
}

Untuk menjalankan function di atas, kita dapat memanggilnnya seperti ini:

1
sayMyFullName("Chike", "Nnamdi", "Mgbemena")

Melihat function panggilan di atas, kita tidak tahu argumen tipe String mana yang sesuai dengan parameter function (walaupun beberapa IDE seperti IntelliJ IDEA dapat membantu kita). Pengguna function harus melihat signature function (atau source code) atau dokumentasi untuk mengetahui parameter yang sesuai dengan masing-masing parameter. 

1
sayMyFullName(firstName = "Chike", middleName = "Nnamdi", lastName = "Mgbemena")

Pada function kedua di atas, kami memberikan nama parameter sebelum nilai argumen. Anda dapat melihat bahwa pemanggilan function ini lebih jelas dan lebih mudah dibaca daripada yang sebelumnya.  Cara memanggil function ini membantu mengurangi kemungkinan adanya bug yang bisa terjadi bila argumen dari tipe yang sama tertukar karena kesalahan. 

Pemanggil juga dapat mengubah urutan parameter menggunakan parameter bernama. Sebagai contoh:

1
sayMyFullName(lastName = "Mgbemena", middleName = "Nnamdi", firstName = "Chike") // will still compile

Pada kode di atas, kita menukar posisi argumen dari firstName dengan lastName. Urutan argumen tidak masalah dengan parameter yang diberi nama karena compiler akan memetakan masing-masing parameter function dengan tepat. 

Parameter Default 

Di Kotlin, kita bisa memberi nilai default function untuk parameter-parameternya. Nilai default ini digunakan jika tidak ada yang ditugaskan ke argumen selama pemanggilan function. Untuk melakukan ini di Java, kita harus membuat metode kelebihan beban yang berbeda.

Pada method calCircumference(), memodifikasi method dengan menambahkan nilai default untuk parameter piMath.PI, constant yang berada dari package java.lang.Math

1
fun calCircumference(radius: Double, pi: Double = Math.PI): Double = (2 * pi) * radius

Ketika kita memanggil function ini, kita dapat melewati nilai perkiraan untuk pi atau menggunakannya secara default.

1
print(calCircumference(24.0)) // used default value for PI and prints 150.79644737231007

2
print(calCircumference(24.0, 3.14)) // passed value for PI and prints 150.72

Perhatikanlah contoh lainnya:

1
fun printName(firstName: String, middleName: String = "N/A", lastName: String) {
2
    println("first name: $firstName - middle name: $middleName - last name: $lastName")
3
}

Dalam kode berikut, kita mencoba memanggil function tersebut, namun tidak akan di-compile:

1
printName("Chike", "Mgbemena") // won't compile

Dalam function panggilan di atas, saya melewati nama depan dan nama belakang saya ke function, dan berharap untuk menggunakan nilai default untuk nama tengah.  Tapi ini tidak akan di-compile karena compiler bingung. Tidak tahu untuk apa argumen "Mgbemena" itu — apakah untuk parameter middleName atau parameter lastName?

Untuk memecahkan masalah tersebut, kita bisa menggabungkan named parameter dan default parameter.

1
printName("Chike", lastName = "Mgbemena") // will now compile

Java Interoperability

Mengingat Java tidak mendukung nilai parameter default dalam method, Anda harus menentukan semua nilai parameter secara eksplisit saat Anda memanggil function Kotlin dari Java. Tapi Kotlin memberi kita fungsionalitas untuk mempermudah dalam pemanggilan Java dengan memberi anotasi pada function Kotlin dengan @JvmOverloads. Anotasi ini akan menginstruksikan compiler Kotlin untuk menghasilkan overloads function Java untuk kita.

Dalam contoh berikut, kami memberi beberapa function calCirumference() dengan @JvmOverloads.

1
@JvmOverloads
2
fun calCircumference(radius: Double, pi: Double = Math.PI): Double = (2 * pi) * radius

Kode berikut dihasilkan oleh compiler Kotlin sehingga pemanggil Java tersebut dapat memilih yang mana yang akan dipanggil.

1
// Java

2
double calCircumference(double radius, double pi);
3
double calCircumference(double radius);

Dalam definisi metode Java yang terakhir dihasilkan, parameter pi dihilangkan. Ini berarti bahwa metode tersebut akan menggunakan nilai pi default. 

Unlimited Arguments

Di Java, kita dapat membuat metode untuk menerima sejumlah argumen yang tidak ditentukan dengan menyertakan elipsis (...) setelah mengetikkan dalam daftar parameter metodenya. Konsep ini juga didukung oleh function Kotlin dengan penggunaan vararg modifier yang diikuti dengan nama parameter. 

1
fun printInts(vararg ints: Int): Unit {
2
    for (n in ints) {
3
        print("$n\t")
4
    }
5
}
6
printInts(1, 2, 3, 4, 5, 6) // will print 1    2  3	4	5	6

Vararg modifier memungkinkan pemanggil untuk masuk dalam daftar argumen yang dipisahkan koma. Di balik layar, daftar argumen ini akan dibungkus dalam sebuah array.

Bila sebuah function memiliki beberapa parameter, parameter vararg biasanya adalah yang terakhir. Hal ini juga memungkinkan untuk memiliki parameter setelah vararg, namun Anda harus menggunakan named parameter untuk menentukannya saat Anda memanggil function. 

1
fun printNumbers(myDouble: Double, myFloat: Float, vararg ints: Int) {
2
    println(myDouble)
3
    println(myFloat)
4
    for (n in ints) {
5
        print("$n\t")
6
    }
7
}
8
printNumbers(1.34, 4.4F, 2, 3, 4, 5, 6) // will compile

Misalnya, pada kode di atas, parameter dengan vararg modifier berada pada posisi terakhir dalam daftar beberapa parameter (inilah yang biasanya kita lakukan).  Tapi bagaimana kalau kita tidak menginginkannya di posisi terakhir? Pada contoh berikut, berada di posisi kedua.

1
fun printNumbers(myDouble: Double, vararg ints: Int, myFloat: Float) {
2
    println(myDouble)
3
    println(myFloat)
4
    for (n in ints) {
5
        print("$n\t")
6
    }
7
}
8
printNumbers(1.34, 2, 3, 4, 5, 6, myFloat = 4.4F) // will compile

9
printNumbers(1.34, ints = 2, 3, 4, 5, 6, myFloat = 4.4F) // will not compile

10
printNumbers(myDouble = 1.34, ints = 2, 3, 4, 5, 6, myFloat = 4.4F) // will also not

11
compile

Seperti yang dapat Anda amati dalam kode yang diperbarui di atas, kami menggunakan named argumen pada parameter terakhir untuk menyelesaikan ini.

Spread Operator

Misalkan kita ingin melewati array bilangan bulat ke function printNumbers(). Function ini mengharapkan nilai yang akan dibuka kembali ke dalam daftar parameter.  Jika Anda mencoba untuk melewatkan array langsung ke printNumbers(), Anda akan melihat bahwa itu tidak akan di-compile.

1
val intsArray: IntArray = intArrayOf(1, 3, 4, 5)
2
printNumbers(1.34, intsArray, myFloat = 4.4F) // won't compile

Untuk mengatasi masalah ini, kita perlu menggunakan operator penyebaran *. Operator ini akan membongkar array dan kemudian melewati elemen individual sebagai argumen ke function untuk kita.

1
val intsArray: IntArray = intArrayOf(1, 3, 4, 5)
2
printNumbers(1.34, *intsArray, myFloat = 4.4F) // will now compile

Dengan memasukkan operator penyebaran * di depan intsArray dalam daftar argumen function, kode sekarang dapat di-compile dan menghasilkan hasil yang sama seperti jika kita telah melewati elemen intsArray sebagai daftar argumen yang dipisahkan koma.

Return Multiple Values

Terkadang kita ingin mengembalikan beberapa nilai dari suatu function. Salah satu cara adalah dengan menggunakan tipe Pair di Kotlin untuk membuat Pair dan kemudian mengembalikannya.  Struktur Pair ini membungkus dua nilai yang nantinya bisa diakses. Tipe Kotlin ini bisa menerima tipe yang Anda berikan pada konstruktornya. Dan, terlebih lagi, kedua tipe ini bahkan tidak perlu sama.

1
fun getUserNameAndState(id: Int): Pair<String?, String?> {
2
    require(id > 0, { "Error: id is less than 0" })
3
4
    val userNames: Map<Int, String> = mapOf(101 to "Chike", 102 to "Segun", 104 to "Jane")
5
    val userStates: Map<Int, String> = mapOf(101 to "Lagos", 102 to "Imo", 104 to "Enugu")
6
7
    val userName = userNames[id]
8
    val userState = userStates[id]
9
    return Pair(userName, userState)
10
}

Pada function di atas, kami membuat Pair baru dengan melewatkan variabel userName dan userState sebagai argumen pertama dan kedua masing-masing ke konstruktornya, dan kemudian mengembalikan Pair ini ke pemanggil.

Hal lain yang perlu diperhatikan adalah kita menggunakan function yang disebut require() pada function getUserNameAndState(). Fungsi penolong ini dari library standar yang digunakan untuk memberi function kepada pemanggil sebuah prasyarat untuk terpenuhi, atau IllegalArgumentException akan dilemparkan (kita akan membahas Exceptions di Kotlin di artikel selanjutnya). Argumen kedua opsional untuk require() adalah function literal yang mengembalikan pesan yang akan ditampilkan jika Exceptions dilempar. Misalnya, memanggil function getUserNameAndState() dan melewati -1 sebagai argumen untuk itu akan memicu:

IntelliJ IDEA code execution resultIntelliJ IDEA code execution resultIntelliJ IDEA code execution result

Retrieving Data From Pair

1
val userNameAndStatePair: Pair<String?, String?> = getUserNameAndState(101)
2
println(userNameAndStatePair.first) // Chike

3
println(userNameAndStatePair.second) // Lagos

Pada kode di atas, kita mengakses nilai first dan second dari tipe Pair dengan menggunakan properti first dan second.

Namun, ada cara yang lebih baik untuk melakukan hal ini: destrukturisasi.

1
val (name, state) = getUserNameAndState(101)
2
println(name) // Chike

3
println(state) // Lagos

Apa yang telah kita lakukan dalam kode yang diperbarui di atas adalah dengan langsung menetapkan nilai pertama dan kedua dari tipe Pair yang dikembalikan ke name variabel dan state masing-masing. Fitur ini disebut deklarasi destrukturisasi

Triple Return Values dan Luar

Nah, bagaimana jika Anda ingin mengembalikan tiga nilai sekaligus? Kotlin menyediakan tipe lain yang berguna yang disebut Triple

1
fun getUserNameStateAndAge(id: Int): Triple<String?, String?, Int> {
2
    require(id > 0, { "id is less than 0" })
3
    
4
    val userNames: Map<Int, String> = mapOf(101 to "Chike", 102 to "Segun", 104 to "Jane")
5
    val userStates: Map<Int, String> = mapOf(101 to "Lagos", 102 to "Imo", 104 to "Enugu")
6
    
7
    val userName = userNames[id]
8
    val userState = userStates[id]
9
    val userAge = 6
10
    return Triple(userNames[id], userStates[id], userAge)
11
}
12
13
val (name, state, age) = getUserNameStateAndAge(101)
14
println(name) // Chike

15
println(state) // Lagos

16
println(age) // 6

Saya yakin beberapa dari Anda bertanya-tanya apa yang harus dilakukan jika Anda ingin mengembalikan lebih dari tiga nilai. Jawaban untuk itu akan di posting selanjutnya, saat kita membahas class data di Kotlin.

Kesimpulan

Dalam tutorial ini, Anda belajar tentang package dan function dasar dalam bahasa pemrograman Kotlin. Dalam tutorial berikutnya di seri Kotlin From Scratch, Anda akan belajar lebih banyak tentang function di Kotlin. Sampai jumpa lagi!

Untuk mempelajari lebih lanjut tentang bahasa Kotlin, saya sarankan untuk mengunjungi dokumentasi Kotlin. Atau lihat beberapa postingan pengembangan aplikasi Android kami yang lain di Envato Tuts+!