Kotlin Android Developer Expert
source : dicoding |
Apa itu Kotlin?
Kotlin adalah sebuah bahasa pemrograman dengan pengetikan statis yang berjalan pada Mesin Virtual Java ataupun menggunakan kompiler LLVM yang dapat pula dikompilasikan ke dalam bentuk kode sumber JavaScript.
Pengembang utamanya berasal dari tim programer JetBrains yang bermarkas di Saint Petersburg, Rusia. JetBrains terkenal dengan produk IntelliJ IDEA, sebuah platform IDE yang sangat powerful dan banyak digunakan oleh Java Developer. Android Studio merupakan sebuah IDE resmi serta khusus dibuat untuk Android Development. Pembuatan IDE ini berdasarkan IntelliJ IDEA.
Kotlin didesain berdasarkan pemahaman pemrograman dari Java Developer serta IntelliJ sebagai IDE utamanya.
Kotlin sangat intuitif dan mudah dipelajari bagi Java Developer. Sebagian besar bahasanya sangat mirip dengan apa yang ada pada Java. Para Java Developer pun dapat mempelajari perbedaan konsep dasar pada Kotlin dalam waktu singkat. Meskipun sintaksisnya tidak kompatibel dengan bahasa Java, Kotlin didesain untuk dapat bekerja sama dengan kode bahasa Java dan bergantung kepada kode bahasa Java, seperti berbagai framework Java yang ada.
Tim Pengembang memutuskan untuk memberi nama “Kotlin”, yakni nama sebuah pulau di Rusia, sebagaimana ”Java” yang berasal dari nama pulau Jawa (atau Java dalam bahasa Inggris) di Indonesia.
Pada Google I/O 2017 Kotlin resmi diumumkan sebagai bahasa pemrograman yang dapat digunakan untuk membuat aplikasi Android. Google menetapkan Kotlin sebagai bahasa kelas satu bagi Android. Maka bersama Java dan C++, Kotlin merupakan bahasa resmi untuk pengembangan aplikasi-aplikasi Android.
Dengan pengukuhan ini Google nyata mendukung Kotlin secara penuh. Google juga akan memastikan bahwa semua fitur baru di Android, framework, IDE dan keseluruhan library, akan dapat bekerja dan terintegrasi baik dengan bahasa pemrograman Kotlin.
Penetapan Kotlin menjadi bahasa first-party pemrograman aplikasi Android ini sesuai dengan aspirasi para developer di komunitas yang telah lama menginginkannya. Keuntungannya adalah kini kita dapat menggunakan bahasa pemograman modern Kotlin untuk membuat aplikasi di Android.
Kotlin mengadakan event Kotlin Conference pertamanya di San Francisco 2 - 3 November 2017. Pada pertemuan tersebut banyak dibahas bagaimana perusahaan-perusahaan besar mengadopsi Kotlin sebagai bahasa pemrograman pada aplikasi Android mereka. Sebut saja Pinterest, Netflix, Gradle, Expedia dan techpreneur global lainnya. Salah satu dari penulis buku ini pun ikut dalam konferensi tersebut. Melalui akun Twitter resminya, panitia Kotlin Conference juga sudah mengumumkan bahwa KotlinConf 2018 akan diadakan pada tanggal 3 - 5 Oktober 2018 di Amsterdam.
Kotlin sudah terintegrasi dengan baik pada IDE Android Studio sejak versi 3.0 (rilis Oktober 2017) dan sekarang versi 3.2.1 (rilis Oktober 2018). Pada bulan Oktober kemarin, JetBrains telah merilis Kotlin versi 1.3 bersamaan dengan beberapa library dan build tools.
Mengapa Kotlin?
Sebelumnya kita telah mengenal apa itu Kotlin dan bagaimana sejarahnya sampai bisa menjadi sebuah bahasa pemrograman baru dalam pengembangan aplikasi Android, pasti Anda bertanya-tanya “Lalu kenapa saya harus mempelajari Kotlin lebih dalam?” Jawabannya adalah karena Kotlin memiliki banyak kelebihan yang memudahkan proses pengembangan aplikasi.
Kotlin merupakan bahasa pemrograman modern yang mudah untuk dipelajari, sederhana dan efisien. Syntax di dalam Kotlin mudah untuk dibaca dan bisa dibilang bahasanya lebih “manusiawi”. Kotlin memiliki konstruksi object-oriented dan functional. Anda dapat menggunakannya baik dengan gaya object-oriented dan functional programming, atau elemen campuran dari keduanya. Dengan dukungan first-class untuk fitur seperti higher-order functions, function types, dan lambda, Kotlin adalah pilihan yang tepat jika Anda ingin mempelajari pemrograman fungsional. Berikut ini beberapa fitur yang membuat bahasa ini lebih unggul:
1. Ringkas (Concise)
Terdapat pengurangan drastis pada jumlah kode boilerplate. Fitur ini memungkinkan kita untuk menuliskan kode yang biasa dipakai berulang-ulang dalam beberapa baris saja.
2. Aman (Safe)
Terhindar dari error classes seperti NullPointerException (NPE) atau yang sering disebut “The Billion Dollar Mistake”. Kotlin akan menempatkan Null Exception pada saat kompilasi sedang berjalan dan secara otomatis menangani semua NPE yang biasa terjadi di saat kompilasi.
3. Dapat dioperasikan secara bersilangan (Interoperable)
Ini artinya kode Anda yang sebelumnya dituliskan dalam Java dapat dipanggil dengan Kotlin. Begitupun sebaliknya, Java juga bisa memanggil fungsi-fungsi yang ada dalam Kotlin. Anda pun bisa menuliskan kode Java di dalam kelas Kotlin dan plugin dari Kotlin akan melakukan konversi ke Kotlin secara otomatis.
4. Dapat digunakan di banyak Tool (Tool-friendly)
Untuk memulai menuliskan kode Anda di dalam bahasa Kotlin, Anda bisa menggunakan Java IDE manapun atau bisa juga menggunakan command line. Tapi sangat disarankan untuk menggunakan IntelliJ yang sudah satu paket dengan Kotlin. Atau untuk pengembangan aplikasi Android, Anda bisa menggunakan Android Studio dengan versi terbaru.
Basic Type
Kita telah mengenal 2 (dua) macam tipe data yaitu primitif (int, long, char, boolean, dll) dan tipe reference (array, string) pada Java. Di dalam Kotlin, semua tipe data tersebut bertindak sebagai object. Beberapa tentang basic type yang perlu Anda pahami pada Kotlin adalah:
Number
Kotlin menangani tipe number mirip dengan bahasa pemrograman Java, namun di dalam Kotlin tidak ada konversi secara implisit dan mungkin akan sedikit berbeda pada beberapa kondisi tertentu. Beberapa tipe bawaan yang merepresentasikan numbers adalah int, double, float, long, short, dan byte. Sedangkan untuk karakter atau char tidak termasuk ke dalam numbers. Perhatikan kode di bawah ini tentang bagaimana cara mendeklarasikan tipe data:
val intNumbers = 3
val doubleNumbers = 27.5
val longNumbers = 8L
val floatNumbers = 2.5F
val hexaNumbers = 0x0F
val byteNambers = 0b010101
Perlu diketahui bahwa Kotlin tidak bisa melakukan konversi secara otomatis untuk masing-masing numbers. Jadi kita perlu secara eksplisit melakukan konversi dengan fungsi yang tersedia. Misalnya Anda ingin melakukan konversi dari int ke double, maka kode yang digunakan adalah:
val intNumbers = 3
val doubleNumbers = intNumbers.toDouble()
Adapun untuk fungsi yang bisa kita gunakan untuk melakukan konversi adalah toInt(), toDouble(), toFloat(), toLong(), toShort(), toByte().
Contoh lain adalah konversi dari String berupa angka menjadi int:
val stringNumber = "333"
val intNumbers = stringNumber.toInt()
Dengan kode di atas Anda bisa mendapatkan nilai angka 333 berupa Integer yang merupakan hasil konversi dari String.
Boolean
Boolean adalah tipe data yang memiliki dua nilai yaitu true dan false. Terdapat 3 jenis operasi dalam boolean, yaitu disjunction (||), conjunction (&&), dan negation (!).
//deklarasi boolean type
val booleanTrue = true
val booleanFalse = false
//contoh operasi pada boolean
val a = 3
val b = 7
val c = 5
val x = a < b && b > c //true
val y = a > b && a < c //false
val z = a < b || a > b //true
Kode di atas menunjukkan cara mendeklarasikan boolean beserta operasi yang ada di dalamnya. Anda bisa menjalankan kode tersebut untuk mengetahui hasilnya.
Strings
Di dalam Kotlin, penulisan string bisa menggunakan tanda petik dua (" ") untuk mendeklarasikan string di dalam satu baris atau triple petik dua (""" """) untuk mendeklarasikan string yang lebih dari satu baris.
val singleLineString = "Hi, dicoding!"
val multiLineString = """ Hi, dicoding,
happy coding!"""
Anda juga bisa menggunakan karakter escape di dalam petik dua untuk mendeklarasikan string yang lebih dari satu baris.
val multiLineString = " Hi, dicoding, \n " +
"happy coding!"
//atau
val multiLineString = " Hi, dicoding, \n happy coding!"
String bisa diakses sebagai array dan bisa diiterasi. Misalnya Anda ingin mengambil satu karakter di dalam sebuah string "Hi, dicoding!" maka Anda bisa menggunakan kode seperti berikut:
val singleLineString = "Hi, dicoding!"
val iterateString = singleLineString[0]
Dari kode di atas, maka kita bisa melihat bahwa value dari iterateString adalah huruf pertama dari string "Hi, dicoding!" yaitu H.
Kotlin juga mendukung string templates yang memungkinkan Anda untuk membuat string yang dinamik. Kita bisa menambahkan variabel dan expressions ke dalam sebuah string. Perhatikan potongan kode berikut:
val queueNumber = 17
val yourQueue = "Your queue number is $queueNumber"
Dari kode di atas, maka value dari yourQueue adalah "Your queue number is 17"
Array
Array dalam Kotlin direpresentasikan oleh kelas Array yang memiliki fungsi get dan set serta properti size. Ada dua cara untuk membuat array, Anda bisa menggunakan arrayOf() atau Array().
Berikut adalah contoh untuk membuat sebuah array dengan menggunakan arrayOf():
val sampleArray = arrayOf(1, 3, 5)
Lalu Anda bisa memanggil elemen dari array tersebut dengan menggunakan sampleArray[i] di mana i adalah indeks dari elemen yang ingin Anda panggil.
Dengan arrayOf() kita juga bisa memasukkan value dengan tipe yang berbeda ke dalam array, contohnya seperti berikut:
val mixArray = arrayOf(1, 3, 5, "odd", true)
Lalu bagaimana jika Anda hanya ingin membuat array dengan satu jenis tipe data? Anda bisa menggunakan fungsi yang lebih spesifik yaitu intArrayOf(), booleanArrayOf(), charArrayOf(), longArrayOf(), shortArrayOf(), byteArrayOf().
Kemudian untuk contoh membuat array dengan konstruktor Array() perhatikan kode berikut:
val numbersArray = Array(4, { i -> i * 3 })
Konstruktor Array() memerlukan size dan fungsi lambda. Pada contoh kode di atas, angka 4 berperan sebagai size. Maka hasil dari kode tersebut adalah kumpulan angka dengan kelipatan 3 dan size-nya berjumlah 4 ([0,3,6,9]).
Variable, dan Properties
Di dalam Kotlin, “Everything is an Object”. Kita tidak akan menemukan tipe primitif seperti yang biasa kita gunakan pada Java. Tentunya ini akan sangat membantu ketika kita ingin memanggil fungsi dan properti pada sebuah variabel. Pada modul ini kita akan membahas tentang Variable dan Properties pada Kotlin.
Variable
Variable didefinisikan dengan val dan var. val mirip dengan final pada Java. Dengan val kita bisa mendeklarasikan sebuah constants atau object yang tidak bisa diganti setelah diinisialisikan.
val company : String = "Dicoding"
Kode di atas menjelaskan bahwa kita telah membuat variable dengan tipe string dan value-nya adalah "Dicoding". Kotlin memungkinkan kita untuk menyederhanakan setiap kode yang kita tulis. Kode tersebut dapat ditulis tanpa menyebutkan tipe data yang diinginkan.
val company = "Dicoding"
Kotlin akan mengetahui bahwa variabel di atas bertipe string. Kode di atas akan tetap berfungsi karena compiler telah secara implisit menyimpulkan tipe tersebut menggunakan type inference. Type inference merupakan sebuah mekanisme yang digunakan oleh compiler untuk mencari tipe dari context. Mekanisme tersebut dapat membantu mengurangi kode boilerplate yang harus Anda tulis. Karena variabel company dideklarasikan menggunakan val, maka kita tidak bisa menggantinya dengan value yang baru.
val company = "Dicoding"
company = "JetBrains" //error, variable tidak bisa diganti
Berbeda dengan var, kita masih bisa mengganti value dari variabel yang sudah diinisialisasikan.
var company = "Dicoding"
company = "JetBrains" //sukses, value dari company adalah “JetBrains”
Perlu diketahui bahwa dalam mendeklarasikan sebuah variabel, sangatlah disarankan untuk menggunakan val. Penggunaan val akan memastikan bahwa variabel yang dibuat tidak akan bisa diganti oleh thread lain. Sehingga ini akan lebih aman jika Anda mengimplementasikan multithreading.
Properties
Sama halnya dengan variable, properties juga dapat dideklarasikan dengan menggunakan val atau var. Secara default, properti sudah menyediakan getter dan setter. Perhatikan potongan kode berikut:
class Student {
var studentName : String = ""
}
Kode di atas menunjukkan bahwa terdapat satu properti studentName dengan tipe string di dalam kelas Student. Atau kita juga bisa menambahkan setter dan getter secara spesifik:
class Student {
var studentName: String = ""
get() = field.toUpperCase()
set(value) {
field = "Name: $value"
}
}
Kemudian properti tersebut bisa diakses dengan kode seperti berikut:
val student = Student()
student.studentName = "rohmen"
val name = student.studentName
Cukup sederhana kan? Kita hanya perlu memanggil nama dari properti tersebut untuk mengakses setter atau getter.
Control Flow
Control Flow pada Kotlin mencakup if, when, for, loops, dan while loops. Pada modul ini Anda akan belajar cara penerapan beberapa macam control flow tersebut di dalam Kotlin.
If expression
Di dalam Kotlin, if merupakan sebuah expression. if akan menjalankan kode jika memiliki kondisi true, dan akan dilewati ketika kondisinya false. Sama seperti bahasa pemrograman lainnya, If expression bisa ditulis seperti berikut:
val a = 3
val b = 2
if (a > b) {
print("a is greater than n")
} else {
print("a is not greater than n")
}
Kita juga bisa menetapkan hasilnya ke dalam sebuah variabel seperti berikut:
val result = if (a > b) a else b
Dengan begitu dapat disimpulkan bahwa if expression selalu mengembalikan value.
Perlu diketahui bahwa Kotlin tidak mendukung ternary operator (condition ? then : else), karena peran dari operator tersebut sudah digantikan dengan if expressions.
When Expression
Kotlin memiliki when expression yang merupakan pengganti dari switch dalam bahasa pemrograman lain seperti Java dan C++. Jika dibandingkan dengan bahasa lain, penulisan when expression lebih sederhana dan fiturnya juga memiliki banyak keunggulan.
Seperti percabangan pada umumnya, kita bisa menambahkan percabangan else, untuk mengatasi ketiadaan kondisi sebelumnya yang sesuai.
val x = 4
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
Pada kode di atas, when akan melakukan pengecekan apakah nilai dari x sama dengan salah satu angka yang ada di dalam percabangan. Jika tidak ada satu pun angka di dalam percabangan yang sama dengan nilai x, maka compiler akan menjalankan kode yang ada di dalam percabangan else.
When expression juga bisa melakukan pengecekan untuk nilai yang ada di dalam range atau collection:
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
Dari kode di atas kita bisa mengetahui apakah nilai x berada di dalam atau luar kisaran angka yang telah ditentukan.
For Loops
Perulangan dengan for memungkinkan kita untuk mengulang objek ketika kondisi yang diberikan dalam keadaan true. Perulangan ini bekerja dengan apapun yang menyediakan iterator seperti range, collection, dan sebagainya. Contoh:
for (number in 1..5) {
print(number)
}
Jika dijalankan, kode di atas akan menampilkan angka 12345.
Kita juga bisa menggunakan fungsi withIndex() untuk mengakses indeks dari masing-masing elemen atau menggunakan properti indices untuk mengakses kisaran indeks yang valid dalam sebuah array. Misalnya kita mempunyai sebuah array berisi bilangan ganjil dan kita ingin mengetahui indeks dari setiap elemen bilangan tersebut, kita bisa menggunakan kode berikut:
val arrayNumbers = intArrayOf(1,3,5,7,9)
//menggunakan withIndex()
for ((index, value) in arrayNumbers.withIndex()) {
print("bilangan $value adalah indeks ke-$index\n")
}
//menggunakan indices
for (index in arrayNumbers.indices) {
print("bilangan ${arrayNumbers[index]} adalah indeks ke-$index\n")
}
Jika kode di atas dijalankan, maka akan menampilkan hasil berikut ini:
bilangan 1 adalah indeks ke-0
bilangan 3 adalah indeks ke-1
bilangan 5 adalah indeks ke-2
bilangan 7 adalah indeks ke-3
bilangan 9 adalah indeks ke-4
While Loops
Perulangan selanjutnya adalah while dan do..while. Kedua perulangan tersebut berjalan seperti biasanya pada bahasa pemrograman lain.
//while
while (condition) {
...
}
//do..while
do {
...
} while (condition)
while akan terlebih dahulu mengecek kondisi, dan jika kondisinya benar, maka perulangan akan dijalankan. Sedangkan do..while akan mengecek kondisi setelah perulangan dijalankan. Contoh lain dari while dan do..while:
//while
while (x > 0) {
x++
}
//do..while
do {
//do something good
} while (x != null)
Classes dan Inheritence
Ketika kita belajar sebuah bahasa pemrograman berorientasi objek, tentunya kita harus memahami konsep sebuah classes. Struktur classes dalam Kotlin sedikit berbeda dan bisa dibilang lebih sederhana jika dibandingkan dengan Java. Untuk mendeklarasikan sebuah classes, cukup dengan kata kunci classyang kemudian diikuti dengan nama kelas tersebut.
class Users {
}
Berbeda dengan Java, default visibility pada Kotlin adalah public. Maka ketika kita ingin mendeklarasikan sebuah public class, kita bisa menghilangkan modifier public.
Setiap kelas di dalam Kotlin memiliki sebuah primary constructor, serta satu atau lebih secondary constructor. Kita bisa menambahkan constructor tambahan pada kondisi tertentu, namun umumnya sebuah kelas hanya membutuhkan satu constructor saja. Primary constructor adalah bagian dari class header yang bisa kita tambahkan setelah nama kelas, diikuti dengan beberapa parameter.
class Users constructor(name : String, email: String){
}
Jika constructor tidak memiliki annotation atau visibility modifier, Anda bisa menghilangkan kata kunci constructor.
class Users (name : String, email: String){
}
Kemudian jika kelas tersebut tidak memiliki konten, Anda bisa menghilangkan bracket.
class Users (name : String, email: String)
Lalu di manakah body dari constructor tersebut? Kita bisa menambahkannya di dalam initializer blocks dengan kata kunci init.
class Users (name : String, email: String){
init {
...
}
}
Selanjutnya, untuk menambahkan constructor tambahan, kita bisa menggunakan kata kunci constructor di dalam bracket.
class Users {
constructor(student: Users) {
...
}
}
Jika kelas tersebut memiliki sebuah primary constructor, maka setiap constructor tambahan harus didelegasikan ke primary constructor. Untuk mendelegasikan constructor lain dari kelas yang sama, cukup gunakan kata kunci this.
class Users(val name: String, val email: String) {
constructor(name: String, email: String, student: Users) : this(name, email) {
...
}
}
Membahas classes, pasti tidak jauh dengan yang namanya Inheritance. Inheritance atau bisa disebut dengan “pewarisan”, adalah sebuah mekanisme yang memungkinkan sebuah subclass mengambil isi atau konten dari superclass.
Semua kelas pada Kotlin memiliki superclass Any, yang merupakan default super untuk sebuah kelas yang tidak mendeklarasikan supertypes. Contoh:
class Users
Kita tidak perlu secara eksplisit meng-extend kelas Any, karena kelas tersebut secara default akan meng-extend kelas Any. Kelas Any mirip namun tidak sama dengan Object pada Java. Any hanya memiliki beberapa method yang sama dengan Object, yaitu equals(), hashCode(), dan toString().
Untuk memahami konsep inheritance/pewarisan, perhatikanlah beberapa contoh kelas berikut:
class Users{
fun userAddress(): String{
return "Bandung"
}
}
class Student : Users(){
override fun userAddress(): String {
return super.userAddress()
}
}
Dua kelas di atas menjelaskan bahwa kelas Student meng-extend kelas Users, namun akan terjadi eror pada kode tersebut. Sebabnya, di dalam Kotlin secara default sebuah kelas dan method akan bernilai final. Maka untuk mengatasinya, kita perlu menambahkan modifier open pada kelas atau method yang akan di-extend.
open class Users{
open fun userAddress(): String{
return "Bandung"
}
}
open class Student : Users(){
override fun userAddress(): String {
return super.userAddress()
}
}
Perlu diketahui bahwa jika kita mengambil alih (override) sebuah anggota dari superclass, maka member yang melakukan override juga akan menjadi open. Dengan demikian kita masih bisa meng-override lagi pada subclass lain. Perhatikan contoh berikut:
open class Users{
open fun userAddress(): String{
return "Bandung"
}
}
open class Student : Users(){
override fun userAddress(): String {
return super.userAddress()
}
}
class InformaticsStudent : Student(){
override fun userAddress(): String {
return super.userAddress()
}
}
Kode di atas menunjukkan bahwa kelas Student telah melakukan override kepada method userAddress() dari kelas Users. Maka method userAddress() masih bisa di-override oleh member lain yang telah meng-extend kelas Student tanpa menambahkan modifier open pada method tersebut. Seperti yang telah dicontohkan di dalam kelas InformaticsStudent di atas, jika Anda tidak ingin method userAddress() bisa di-override lagi, Anda harus menandainya dengan kata kunci final.
open class Student : Users(){
final override fun userAddress(): String {
return super.userAddress()
}
}
Beberapa kelas mungkin dideklarasikan sebagai Abstract Classes. Jenis kelas ini merupakan kelas yang tidak utuh tanpa adanya subclass non-abstract yang bisa dipakai untuk membuat objek. Kita bisa melakukan override member dari kelas atau method non-abstract pada sebuah kelas abstract :
open class Users{
open fun userAddress(){}
}
abstract class Student : Users(){
override abstract fun userAddress()
}
Tipe-tipe Classes
Terdapat beberapa tipe dari kelas (classes) pada Kotlin yang penting untuk Anda ketahui. Beberapa kelas tersebut diantaranya adalah Data Classes, Nested Classes, Enum Classes, dan Sealed Classes. Pada modul ini akan kita akan mempelajari tentang Nested Classes, Enum Classes, dan Sealed Classes. Sedangkan Data Classes akan dijelaskan secara terpisah.
Nested Classes
Seperti halnya Java, Kotlin memungkinkan kita untuk mendefinisikan sebuah kelas di dalam sebuah kelas yang disebut dengan Nested Class atau Inner Class. Nested Class ini memiliki hak tersendiri untuk mengakses apa yang ada pada Outer Class-nya, sekalipun ia memiliki modifierprivate. Sebaliknya, Outer Class tidak bisa mengakses apa yang ada pada Inner Class.
class User {
class Name
}
Untuk mengakses sebuah Nested Class pada Kotlin, caranya sedikit berbeda dengan Java. Sebabnya, kita harus menambahkan modifier inner untuk menandai bahwa kelas tersebut merupakan sebuah Nested Class. Ini dilakukan agar kelas yang kita tandai sebagai Nested Class dapat diakses dan mengakses apa yang ada pada kelas yang lain. Termasuk juga bagaimana cara membuat sebuah Nested Class.
class User {
inner class Name(private val name: String) {
fun printName(){
println("Your Name Is $name")
}
}
}
Untuk mengaksesnya kita perlu membuat instance dari Outer Class nya seperti berikut ini:
val user = User()
user.Name("Alfian Yusuf").printName()
user.Name("Alfian Abdullah").printName()
Atau kita bisa langsung membuat instance dari Nested Class tersebut.
val name = User().Name("Alfian yusuf abdullah")
name.printName()
Enum Classes
Enum merupakan kumpulan objek yang telah didefinisikan menjadi tipe data constant. Objek yang telah didefinisikan menjadi tipe data Enum, dapat mengakses attribute atau method di dalam kelas Enum itu sendiri. Konsep ini sama halnya seperti Array. Bedanya, Enum berbentuk constant. Fungsi paling mendasar dari implementasi sebuah type-safe Enum adalah sebagai berikut:
enum class Gender{
MALE , FEMALE
}
Setiap constant berbentuk objek. Setiap objek dipisahkan oleh koma, karena setiap objek merupakan instance dari kelas Enum. Oleh karena itu, kita dapat menginisialisasi seperti berikut:
enum class User(field: String){
NAME("Alfian Yusuf Abdullah"),
EMAIL("alfian@dicoding.com"),
PHONE("082208220822")
}
Objek dari sebuah Enum sendiri dapat mendeklarasikan sebuah Anonymous Classes.
enum class User(val field: String) {
NAME("Alfian Yusuf Abdullah") {
override fun print() {
println("Your Name is $field")
}
},
EMAIL("alfian@dicoding.com") {
override fun print() {
println("Your Email is $field")
}
},
PHONE("082208220822") {
override fun print() {
println("Your Phone is $field")
}
};
abstract fun print()
}
Sama seperti pada Java, Enum di Kotlin juga memiliki synthetic method yang memungkinkan kita untuk melampirkan constant dan mendapatkan constant itu sendiri berdasarkan namanya.
User.valueOf(value: String): User
User.values() : Array<User>
Fungsi valueOf() akan menyebabkan IllegalArgumentException jika nilai yang ditentukan tidak sesuai dengan constant yang sudah dideklarasikan di dalam kelas Enum.
Terhitung dari Kotlin versi 1.1, fungsi valueOf() memungkinkan kita untuk mengakses constant yang berada dalam kelas Enum. Metodenya lebih umum, yakni menggunakan fungsi enumValues() dan enumValueOf().
enum class Gender{ MALE , FEMALE}
print(enumValues<Gender>().joinToString { it.name }) /// MALE, FEMALE
Setiap constant memiliki properti untuk mendapatkan nama serta posisinya di dalam kelas Enum yang sebelumnya sudah dideklarasi.
Sealed Classes
Beberapa catatan penting dari Sealed Class:
Semua subclass dari Sealed Class harus berada pada berkas yang sama di mana Sealed Class tersebut dideklarasikan.
Secara default Sealed Class memiliki modifier abstract.
Sealed Class tidak diijinkan untuk memiliki non-private constructor karena secara default Sealed Class memiliki private constructor.
Berikut ini contoh dari Sealed Class. Kita akan membuat Sealed Class Operation di mana terdapat kelas untuk menerapkan operasi bilangan bulat.
sealed class Operation {
class Add(val value: Int) : Operation()
class Divide(val value: Int) : Operation()
class Multiply(val value: Int) : Operation()
class Substract(val value: Int) : Operation()
}
Selanjutnya kita akan menggunakan when expression untuk mengecek type apa yang digunakan dari kelas Operation seperti berikut.
fun execute(x: Int, operation: Operation): Int = when (operation) {
is Operation.Add -> operation.value + x
is Operation.Divide -> operation.value / x
is Operation.Substract -> operation.value - x
is Operation.Multiply -> operation.value * x
}
Tidak perlu lagi menggunakan elsestatement karena kita sudah memasukkan semua tipe dari kelas Operation. Lain halnya jika kita tidak memasukkan salah satu tipe yang menjadi bagian dari Sealed Classes. Akibatnya, akan terjadi error pada whenexpression dan program tidak bisa dijalankan.
Selanjutnya kita akan menguji fungsi di atas seperti berikut.
val operation = Operation.Add(10)
val result = execute(10, operation)
print("hasil $result")
Data Classes
Kelas Data (Data Classes) adalah jenis kelas yang dapat menghindarkan kita dari boilerplate di Java saat kita membuat POJO. Kelas ini digunakan untuk menjaga keadaan atau state. Operasi yang dilakukan pun sangat sederhana. Salah satu ciri dari sebuah data classes adalah di dalamnya terdapat getter dan setter untuk mengakses nilai suatu properti. Berbeda dengan Java, pembuatan data classes pada Kotlin lebih sederhan. Anda bisa menuliskannya dalam 1 (satu) baris saja. Contoh:
data class Student(var name:String = "Rohmen",var major:String,var phone:String)
Dengan sebaris kode di atas, Anda sudah bisa memanfaatkan constructor, getter, dan setter dari data classes Student.
Cara penggunaannya pun sangatlah mudah, perhatikan contoh berikut:
val student = Student("Rohmen", "Informatics Engineering", "085xxxxxxxxx")
println("Your name is ${student.name}")
println("Your major is ${student.major}")
println("Your phone is ${student.phone}")
Dengan kode di atas, Anda sudah bisa memasukkan dan memanggil data dari sebuah data classes tanpa perlu menuliskan getter dan setter karena sudah ditangani oleh Kotlin property. Tentunya ini akan menghemat waktu Anda dalam menuliskan kode. Jika Anda menjalankan kode di atas, maka hasilnya akan seperti berikut ini:
Your name is Rohmen
Your major is Informatics Engineering
Your phone is 085xxxxxxxxx
Anda juga bisa menentukan properti dalam sebuah data classes sebagai val (immutable) sehingga properti tersebut akan menjadi read-only.
data class Student(val name:String,val major:String,val phone:String)
Data classes juga memungkinkan kita untuk mengatur nilai default dari sebuah properti:
data class Student(val name:String= "Rohmen", val major:String,val phone:String)
Data classes memiliki beberapa fungsi tambahan yang bisa kita gunakan, beberapa fungsi tersebut adalah:
equals(): kita dapat membandingkan nilai dari kedua objek untuk memastikan apakah kedua objek tersebut identik atau tidak.
hashCode(): kita dapat memperoleh kode hash secara gratis, dan dapat dihitung dari nilai yang kita berikan.
copy(): kita dapat menyalin sebuah objek ataupun memodifikasi properti dari objek yang kita inginkan.
Fungsi bernomor yang dapat digunakan untuk memetakan objek menjadi variabel.
Menyalin Data Classes dengan Modifikasi
Saat kita menentukan sebuah properti pada data classes menggunakan immutability, maka kita membutuhkan sebuah instance baru untuk mengubah nilai dari suatu objek. Dengan demikian kita harus memodifikasi properti yang kita maksud. Tugas ini akan berulang dan membuat kode yang kita tulis jauh dari paradigma clean code.
Untuk mengatasinya, kita bisa menggunakan fungsi copy() yang mampu menyalin sebuah objek ataupun memodifikasi properti dari objek yang kita inginkan.
Sebagai contoh, jika kita ingin memodifikasi properti phone pada data classes Student, kita bisa melakukan langkah berikut :
val student = Student("Rohmen", "Informatics Engineering", "085xxxxxxxxx")
val studentA = student.copy(phone = "085878xxxxx")
Pada contoh di atas, kita telah mengubah nilai dari properti phone, dengan cara menduplikasi student menjadi studentA dan mengubah nilai phone menjadi “085878xxxxxx”. Tentunya kita tidak mengubah nilai lain pada student.
Memetakan Objek Menjadi Variabel
Proses pemetaan objek menjadi sebuah variabel, biasa kita kenal dengan istilah destructuring declarations, di mana setiap properti di dalam sebuah objek dipetakan ke dalam sebuah variabel. Contoh seperti sintaks sebelumnya:
val student = Student("Rohmen", "Informatics Engineering", "085878xxxxxx")
val (name, major, phone) = student
Sebuah destructuring declaration tersebut dikompilasi ke dalam kode berikut:
val name = student.component1()
val major = student.component2()
val phone = student.component3()
Fungsi component1(), component2(), dan component3() adalah contoh lain dari prinsip konvensi yang banyak digunakan pada Kotlin. Apapun bisa berada di sisi kanan dari destructuring declaration, selama jumlah komponen yang dibutuhkan dapat dipanggil di atasnya.
Perhatikan bahwa fungsi compnentN() harus ditandai dengan operator agar bisa digunakan dalam proses pemetaan objek.
Visibility Modifier
Modifier pada Kotlin sedikit berbeda dengan bahasa induknya (Java). Pada Kotlin, default modifier yang digunakan adalah public. Kita tidak perlu menuliskan modifier itu ketika modifier yang diinginkan adalah public. Tentunya ini bisa menghemat waktu dalam penulisan kode.
Terdapat 4 (empat) visibility modifiers pada Kotlin, yaitu public, private, protected, dan internal. Semua modifiers bisa digunakan untuk classes, objects, constructors, functions, dan properties beserta setter yang dimiliki.
Public
public adalah modifier yang terbuka untuk umum, dengan artian setiap anggota yang diberi modifier public dapat diakses dari mana saja. Tentunya ada beberapa batasan, misalnya anggota dengan modifier public yang ada di dalam kelas dengan modifier private hanya bisa diakses di dalam kelas itu saja.
public class Users {
}
Kode di atas adalah contoh penerapan modifier public pada sebuah kelas. Karena public adalah default modifier, maka kode tersebut bisa dituliskan seperti berikut:
class Users {
}
Private
Modifier ini adalah kebalikan dari modifier public. Jika public dapat diakses dari mana saja, maka modifier private ini hanya bisa diakses dari dalam berkas (file) yang sama. Jadi ketika Anda mendeklarasikan sebuah kelas dengan modifier private, maka kelas tersebut tidak akan bisa diakses dari luar berkas, sekalipun Anda sudah meng-extend kelas tersebut.
private class Users {
private val name = "rohmen"
private val doSomething() {
}
}
Pada contoh kode di atas, kelas Users dapat diakses dari dalam berkas (file) yang sama dan untuk name dan doSomething() hanya dapat diakses di dalam kelas Users.
Protected
Modifier ini hanya bisa digunakan untuk anggota di dalam sebuah kelas dan interface. protected tidak bisa digunakan pada package member seperti class, object, dan yang lainnya. Ia memiliki sifat yang sama seperti modifier private, namun modifier protected bisa diakses dari anggota subclass.
open class User {
protected val name = "rohmen"
}
Kita memiliki protected variable pada kelas User. Maka variabel tersebut bisa diakses dari kelas lain yang meng-extend kelas User.
class Students : User() {
val studentName = name
}
Internal
Kotlin telah mendukung modifier baru yang belum ada pada Java, yaitu internal. Modifier ini memungkinkan untuk mengakses kode yang dideklarasikan dalam satu modul. Kita bisa mengakses sebuah internal classes dalam kelas lain pada satu modul, tapi kelas tersebut tidak bisa diakses dari modul lain.
Untuk sebuah anggota yang diberi modifier internal, kita juga bisa mengaksesnya dari kelas lain yang berada dalam satu modul, namun tergantung pada visibility dari scope-nya. Sebagai contoh:
internal class Students {
}
Kelas tersebut bisa diakses dari kelas lain yang berada dalam satu modul. Contoh lain:
class User {
internal val id = 17
}
Pada contoh di atas terdapat id dengan modifier internal, maka variabel tersebut bisa diakses dari modul yang sama. Namun jika kita mengubah modifier dari kelas tersebut menjadi private, maka akses dari variabel id akan menjadi terbatas.
Extensions
Kotlin memungkinkan kita untuk meng-extend sebuah kelas dengan fungsi baru tanpa harus mewarisi (inherit) kelasnya. Hal ini dilakukan dengan deklarasi khusus yang disebut dengan Extensions. Terdapat 2 (dua) extension yang didukung oleh Kotlin yaitu extension functions dan extension properties.
Extension Functions
Fungsi ini membantu kita untuk memperluas fungsionalitas pada sebuah kelas tanpa harus menyentuh kode dalam kelas tersebut. Contohnya ketika ingin menambahkan visibility pada sebuah view, Anda cukup membuat fungsi baru seperti berikut:
fun View.visible() {
visibility = View.VISIBLE
}
Dengan begitu fungsi visible yang sudah kita buat tersebut bisa digunakan secara berulang.
Lalu untuk menerapkan fungsi tersebut ke dalam sebuah view, Anda bisa menggunakan kode seperti berikut:
button.visible()
Contoh lain, Anda bisa membuat fungsi baru pada kelas Date untuk mengetahui apakah hari ini adalah hari Selasa dengan kode berikut:
fun Date.isTuesday(): Boolean{
return getDay() == 2
}
val date = Date()
println(date.isTuesday())
Extension Properties
Sama halnya dengan function, Kotlin juga mendukung Extension Properties:
val <T> List<T>.lastIndex: Int
get() = size - 1
Perlu diketahui bahwa extensions tidak benar-benar menambahkan sebuah anggota atau fungsi baru ke dalam kelas. Maka Extension Properties hanya bisa didefinisikan dengan cara menyediakan getter atau setter secara eksplisit.
Generics
Generics adalah fungsi yang memungkinkan sebuah kelas (class) atau interface menjadi tipe parameter yang bisa digunakan untuk berbagai macam tipe data. Dengan generics, kita bisa membuat functions atau types yang hanya berbeda dalam hal parameter yang digunakan menjadi reusable. Perhatikan contoh kode berikut:
class TypedClass<T>(parameter: T) {
val value: T = parameter
}
Potongan kode di atas adalah sebuah kelas dengan generic type. Kita bisa menginisialisasikan kelas tersebut dengan type apapun. Misalnya string atau integer, lalu secara otomatis parameternya akan menyesuaikan tipe yang diinisialisasikan. Berikut adalah contoh penggunaan kelas tersebut:
val stringType = TypedClass<String>("Hi Kotlin!")
val intType = TypedClass<Int>(7)
val nullType = TypedClass<String?>(null)
Seperti biasa, Kotlin memberikan kita keleluasaan untuk menuliskan kode dengan lebih sederhana. Kita bisa menghilangkan tipe dari parameternya. Sehingga kodenya menjadi seperti berikut:
val stringType = TypedClass("Hi Kotlin!")
val intType = TypedClass(7)
val nullType = TypedClass<String?>(null)
Untuk variabel atau objek yang menerima null reference, kita tetap harus menentukan tipe parameternya dengan spesifik.
Variance
Terdapat dua kata kunci di dalam generics, yaitu in dan out. Kedua kata kunci tersebut dapat menangani situasi yang kurang restriktif saat membuat class atau interface. Kata kunci in digunakan untuk contravariant, sedangkan kata kunci out digunakan untuk covariant. Perhatikan contoh penggunaan kata kunci in berikut:
class TypedClass<in T> {
fun toString(value: T): String {
return value.toString()
}
}
Kita bisa menggunakan kata kunci in pada generic type ketika kita ingin menetapkannya ke reference dari subtype-nya. Kata kunci in hanya bisa digunakan pada tipe parameter yang dikonsumsi, dan tidak untuk diproduksi.
Lebih lanjut, untuk penggunaan kata kunci out, perhatikan kode berikut:
class TypedClass<out T>(private val value: T) {
fun get(): T {
return value
}
}
Berbeda dengan kata kunci in, kita bisa menetapkan sebuah reference ke salah satu supertypes-nya. Nilai yang dihasilkan dari fungsi tersebut hanya bisa diproduksi oleh kelas yang diberikan namun tidak untuk dikonsumsi.
Delegated Properties
Delegated Properties dijalankan dengan mendeklarasikan properti dan delegasi yang digunakannya. Terdapat kata kunci by yang menunjukkan bahwa properti dikendalikan oleh delegasi yang diberikan.
Ada beberapa jenis properti, di antaranya adalah lazy properties dan observable properties. Meskipun kita bisa menggunakannya secara manual setiap saat kita membutuhkan, akan lebih baik jika kita menerapkannya sekali saja. Lalu, kita bisa memanggilnya kapanpun. Perhatikan kode berikut:
class Example {
var p: String by Delegate()
}
Struktur syntax di atas adalah val/var <property name>: <Type> by <Expression>. Lalu yang berperan sebagai delegate adalah ekspresi yang dituliskan setelah kata kunci by, karena ketika kita menggunakan get atau set dari sebuah properti, maka nilai dari get atau set dari properti yang didelegasikan tersebut akan dipanggil. Sebagai contoh:
class Delegate<T> {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return ...
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
...
}
}
T di atas adalah jenis properti yang mendelegasikan behavior atau perilakunya. Fungsi getValue akan menerima referensi ke kelas dan metadata dari properti. Lalu fungsi setValue juga menerima nilai yang ditugaskan. Dan jika properti dideklarasikan sebagai val (immutable), maka kita hanya memerlukan fungsi getValue saja.
Standard Delegated
Di dalam Kotlin Standard Library terdapat sepaket Standard Delegated yang siap untuk digunakan. Berikut adalah beberapa standard delegated yang umum digunakan:
Lazy
Lazy delegates memungkinkan nilai properti untuk dikomputasi hanya saat pertama kali diakses dan kemudian dimasukkan ke dalam cache. Sebagai contoh:
val lazyValue: String by lazy {
println("computed!")
"Hi Kotlin!"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
Dalam contoh di atas, kode println("computed!") tidak benar-benar dijalankan. Kode tersebut akan dijalankan untuk pertama kalinya ketika fungsi lazyValue dipanggil di dalam method main. Maka ketika semua kode di atas dijalankan, compiler hanya akan menampilkan hasil berikut:
computed!
Hi Kotlin!
Hi Kotlin!
Observable
Observable delegates memungkinkan untuk sebuah fungsi dijalankan kapanpun ketika terdapat perubahan pada nilai properti. Sebagai contoh:
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
Jika Anda menjalankan kode di atas, hasil yang tampil adalah sebagai berikut :
<no name> -> first
first -> second
Di dalam observable terdapat vetoable yang memungkinkan kita untuk menentukan apakah nilainya harus disimpan atau tidak. Vetoable dapat digunakan untuk memeriksa beberapa kondisi sebelum menyimpan nilai. Fungsi vetoable adalah sebuah standard library yang bekerja dengan cara yang mirip dengan observable, tetapi dengan dua perbedaan utama, yaitu:
Lambda dari sebuah argumen dipanggil sebelum nilai baru ditetapkan.
Memungkinkan fungsi lambda dari deklarasi untuk memutuskan apakah nilai baru harus diterima atau ditolak.
Sebagai contoh, jika kita memiliki asumsi bahwa sebuah list harus selalu berisi jumlah item yang lebih banyak daripada sebelumnya, maka kita akan mendefinisikan vetoable berikut:
var list: List<String> by Delegates.vetoable(emptyList()){
_, old, new ->new.size > old.size
}
Dengan kode di atas, jika jumlah item dari list yang baru lebih sedikit atau sama dengan list yang lama, maka nilainya tidak akan berubah. Jadi, kita bisa memperlakukan vetoable seperti observable, yang juga memutuskan apakah nilainya harus diubah atau tidak.
Menyimpan Properties ke dalam Map
Sebuah studi kasus umum yang sering dijumpai yakni tentang bagaimana cara menyimpan sebuah properti ke dalam map. Misalnya bagaimana menguraikan JSON atau beberapa hal lainnya yang dinamik? Jawabannya, Anda bisa menggunakan instance dari map itu sendiri sebagai delegasi untuk properti yang didelegasikan. Perhatikan kode berikut:
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
Maka untuk memasukkan sebuah nilai ke dalam setiap variabel tersebut, Anda bisa menggunakan kode seperti di bawah ini:
val user = User(mapOf(
"name" to "Rohmen",
"age" to 22
))
Lalu untuk memanggil nilai dari variabel di atas, Anda bisa menggunakan user.name atau user.age.
Functions
Di dalam Kotlin, function atau yang sering kita sebut sebagai method (dalam Java) dideklarasikan dengan kata kunci fun seperti contoh berikut:
fun sum(x: Int, y: Int): Int{
return x + y
}
Pada contoh kode di atas, kita mendefinisikan sebuah fungsi yang bernama sum dengan 2 (dua) parameter yang bertipe integer. Fungsi tersebut akan mengembalikan nilai dengan tipe integer, yakni hasil penjumlahan kedua parameternya. Fungsi tersebut mengembalikan nilai yang bisa dikalkulasikan dengan satu ekspresi. Oleh karena itu, kita bisa mengubahnya menjadi single line functions. Caranya adalah dengan menghilangkan bracket, sementara untuk body bisa ditentukan setelah tanda "=".
fun sum(x: Int, y: Int) = x + y
Di dalam Kotlin, kita juga bisa menentukan argumen secara default untuk parameternya:
fun sum(x: Int, y: Int = 10) = x + y
Lalu untuk memanggil fungsi tersebut bisa menggunakan pendekatan tradisional seperti berikut:
val total = sum(2,7)
Anda juga bisa memanggil fungsi dari kelas lain dengan cara mendeklarasikan instance dari kelas tersebut dan kemudian memanggil fungsinya seperti contoh berikut:
val total = ClassName().sum(2,7)
Function pada Kotlin selalu mengembalikan sebuah value. Jadi, ketika Anda tidak menentukan value yang akan dikembalikan, maka secara otomatis fungsi tersebut akan mengembalikan Unit (atau yang kita kenal sebagai Void pada Java). Perhatikan fungsi pada contoh kode berikut:
fun hello(name: String): Unit {
print("Hello $name")
}
Fungsi di atas memiliki tipe pengembalian Unit, karena tidak mengembalikan nilai yang signifikan.
Lambda
Lambda Expressions bisa disebut dengan anonymous function atau function literal, yaitu sebuah fungsi yang tidak dideklarasikan. Lambda juga tidak terkait kepada entitas apapun termasuk kelas, objek, atau interface. Lambda sangat berguna karena dapat membuat penulisan kode menjadi lebih mudah dan sederhana. Beberapa karakteristik Lambda yang harus diketahui adalah:
Selalu terdapat kurung kurawal {}.
Tidak mempunyai kata kunci fun.
Tidak memiliki visibility modifier seperti public, private, maupun protected.
Tidak memiliki nama fungsi, karena Lambda bersifat anonymous.
Parameter tidak berada di dalam tanda kurung ().
Tidak mengembalikan tipe yang spesifik, karena tipe akan ditentukan oleh compiler.
Lalu bagaimana cara untuk menggunakan Lambda? Perhatikan beberapa contoh kode di bawah.
val message = { println("Happy to learn Kotlin!") }
Pada kode di atas kita telah membuat sebuah fungsi tanpa parameter dengan Lambda. Penandanya adalah sepasang kurung kurawal {} sebagai pembuka dan penutup fungsi. Fungsi tersebut telah kita tetapkan sebagai sebuah variabel message. Kemudian kita bisa menjalankan Lambda tersebut dengan memanggil message() dan compiler akan menampilkan teks "Happy to learn Kotlin!".
Kita juga bisa menambahkan sebuah parameter ke dalam Lambda.
val message = { params: String -> println(params) }
Pada kode di atas kita telah membuat fungsi Lambda dengan menambahkan parameter params yang bertipe string dan diikuti dengan tanda panah ->. Tanda -> tersebut berfungsi untuk memisahkan antara parameter dengan body. Kemudian kita bisa mengeksekusi fungsi tersebut, misalnya dengan memanggil message("I love Kotlin"). Untuk menambahkan beberapa parameter, kita bisa menggunakan tanda koma (,) sebagai pemisah antar parameter, contoh:
val hitungLuas = { a: Int, b: Int -> a * b}
Terdapat 2 parameter dengan tipe integer dari fungsi Lambda di atas. Kita bisa menggunakan fungsi tersebut misalnya dengan memanggil hitungLuas(2,3).
Masih banyak lagi yang bisa dilakukan dengan Lambda. Jika Anda mengembangkan aplikasi Android, pasti tidak asing dengan satu interface bernama setOnClickListener. Interface tersebut berguna untuk memberikan aksi klik pada sebuah komponen view. Misalnya Anda menginginkan sebuah tombol agar bisa diklik dan menjalankan sebuah fungsi, contoh penulisan kodenya adalah seperti berikut ini:
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
...
}
});
Lihat berapa jumlah baris kode yang harus dituliskan hanya untuk menambahkan aksi klik pada sebuah tombol. Kode di atas mengharuskan Anda untuk membuat sebuah kelas anonymous dan menerapkannya ke dalam interface. Sementara dengan Lambda, Anda cukup menuliskan kode sederhana seperti ini:
view.setOnClickListener({view -> //aksi yang diinginkan})
Kode menjadi lebih ringkas dan mudah untuk dimengerti, bukan?
Higher-Order Function
Semua fungsi di dalam Kotlin merupakan first-class function yang artinya fungsi tersebut dapat:
Disimpan dalam sebuah variabel maupun struktur data;
Dilewatkan sebagai argumen, atau;
Dikembalikan dari sebuah Higher-Order Functions lainnya.
Apakah itu higher-order functions? Ia merupakan fungsi yang menggunakan fungsi lainnya sebagai parameter, menjadikan fungsi sebagai nilai kembaliannya, ataupun keduanya.
Mari kita perhatikan contoh berikut:
fun getNickname(fullName: String, nickName: String, yourName: (String, String) -> String){
val result = yourName(fullName, nickName)
println(result)
}
Fungsi getNickname di atas merupakan sebuah Higher-Order Function, di mana fungsi tersebut menjadikan fungsi lain sebagai salah satu parameternya. Fungsi lain yang dimaksud adalah fungsi yourName yang merupakan sebuah Lambda. Sekarang kita akan mencoba untuk mengakses Higher-Order Functions di atas. Pertama, buat terlebih dahulu sebuah Lambda expressions yang nantinya akan dijadikan sebagai parameter ketiga dari fungsi getNickname.
val name: (String, String) -> String = {realName, heroName -> "My name is $realName, you can call me $heroName"}
Setelah itu, kita bisa memanggil fungsi getNickname dengan mengisi semua parameter yang dibutuhkan:
getNickname("Nur Rohman", "Rohmen", name)
Bisa diperhatikan bahwa pada fungsi di atas kita telah melewatkan 3 parameter di mana parameter ketiga merupakan sebuah Lambda expressions atau literal function.
Selain itu, kita juga bisa melewatkan Lambda secara langsung di dalam Higher-Order Function seperti berikut:
getNickname("Nur Rohman", "Rohmen", {
realName, heroName -> "My name is $realName, you can call me $heroName"
})
Jika dijalankan, kode di atas akan menampilkan hasil yang sama dengan kode sebelumnya. Atau Anda juga bisa menggunakan cara lain, yaitu menempatkan parameter ketiga sebagai body dari fungsi tersebut seperti berikut:
getNickname("Nur Rohman", "Rohmen") {
realName, heroName -> "My name is $realName, you can call me $heroName"
}
Dengan demikian kesimpulannya, Higher-Order Function memungkinkan kita untuk menuliskan kode secara lebih deklaratif.
Null Safety
Sebagai seorang programmer, terutama yang sering menggunakan bahasa pemrograman Java, pasti familiar dengan “NullPointerException (NPE)” atau yang sering disebut dengan “The Billion Dollar Mistake”. NPE kerap mengharuskan kita untuk selalu mengecek apakah pada suatu objek terdapat potensi null atau tidak.
Pada Kotlin, Anda tidak perlu berurusan lagi dengan masalah NPE ini. Seperti yang sudah dijelaskan sebelumnya, Kotlin memiliki fitur Null Safety sebagai salah satu keunggulannya. Kotlin akan menempatkan Null Exception pada saat kompilasi dan secara otomatis menangani semua NPE yang biasa terjadi. Kotlin juga mampu membedakan antara objek yang boleh null atau tidak boleh null pada saat objek itu dibuat. Dengan demikian bisa dipastikan bahwa Kotlin aman dari NPE.
Perhatikan beberapa contoh kode di bawah untuk mempelajari Null Safety lebih lanjut.
var a: String = "dicoding"
a = null // compilation error
Baris ke-2 dari kode di atas akan langsung mengalami eror karena secara default objek di dalam Kotlin bersifat non-null references jadi tidak bisa diisi dengan null. Lalu bagaimana untuk mengizinkan null pada sebuah objek? Anda bisa mendeklarasikan objek sebagai nullable dengan menambahkan tanda ? setelah tipe objek.
var a: String? = "kotlin"
a = null
Dengan begitu variabel a tersebut bisa berisi null.
Memeriksa Null
Ketika sebuah objek bersifat nullable dan kita ingin mengakses properti dari objek tersebut, maka kita harus memeriksa terlebih dahulu apakah objek tersebut berisi null atau tidak. Ada beberapa cara untuk memeriksa null pada Kotlin, antara lain:
Menggunakan Kondisi
Ini adalah cara tradisional yang biasanya digunakan. Anda bisa mengecek apakah suatu objek berisi null dengan kondisi if/else.
if (a != null && a.length > 0) {
print("String of length ${a.length}")
} else {
print("Empty string")
}
Safe Calls
Cara kedua adalah menggunakan safe calls atau tanda ?. misalnya:
a?.length
Kode tersebut akan memberikan nilai dari a.length jika a tidak sama dengan null, namun jika ternyata a sama dengan null, maka compiler tidak akan melakukan apapun.
Elvis Operator
Salah satu skenario paling umum ketika kita memiliki tipe nullable adalah menggunakan nilainya ketika nilai tersebut tidak null. Sebagai contoh:
val company: String?
if (user != null){
company = user.company
} else{
company = "Default name"
}
Pada contoh kode di atas, kita melakukan pengecekan null dengan menggunakan kondisi if else. Kotlin memiliki Elvis Operator yang memungkinkan kita untuk menyederhanakan penulisan kode tersebut. Operator elvis dapat dituliskan dengan tanda ?: seperti berikut:
val name: String = user.company ?: "default name"
Jika user.company tidak bernilai null, maka operator elvis akan mengembalikan nilainya ke dalam variabel name. Namun jika user.company bernilai null, maka "default name" lah yang akan dikembalikan.
!! Operator
Cara ini tidak disarankan karena akan memaksa suatu objek menjadi non-null dan akan mengakibatkan NPE jika nilai dari objek tersebut adalah null. Sebagai contoh:
val b = a!!.length
Jika nilai dari a adalah null maka compiler akan menampilkan NPE.
Selain itu, kita juga bisa memeriksa null pada sebuah collections dengan menggunakan fungsi filterNotNull. Tujuannya untuk menghilangkan null dari sebuah collections. Perhatikan kode berikut:
val nullableList: List<Int?> = listOf(1, 3, null, 7, 9)
val intList: List<Int> = nullableList.filterNotNull()
Maka nilai dari intList di atas adalah 1,3,7,9.
Konversi Java ke Kotlin
Dengan Kotlin Plugins yang sudah diterapkan pada proyek, Anda juga bisa mengubah kode Java menjadi kode Kotlin. Caranya sangat sederhana, yakni hanya dengan menekan shortcut Ctrl + Shift + Alt + K, otomatis kode Java akan langsung berubah menjadi kode Kotlin. Misalnya Anda mempunyai class MainActivity.Java dengan kode seperti di bawah ini:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textHello = findViewById(R.id.text_hello);
textHello.setText("Hello Kotlin!");
}
}
Maka setelah Anda menekan shortcut tadi, kode tersebut akan menjadi seperti ini:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textHello = findViewById<TextView>(R.id.text_hello)
textHello.text = "Hello Kotlin!"
}
}
Menjalankan Project Hello Kotlin!
Terakhir untuk memastikan proyek pertama Anda berjalan dengan baik, bukalah berkas activity_main.xml dan tambahkan attribute id pada TextView seperti berikut:
<TextView
android:id="@+id/text_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Lalu pada kelas MainActivity tambahkan kode berikut ke dalam method onCreate:
val textHello = findViewById<TextView>(R.id.text_hello)
textHello.text = "Hello Kotlin!"
Reference :
dicoding
Kotlin Android Developer Expert
To keep in touch :
Instagram : @patrick_vivo
Pinterest : Patrick Ananta
Twitter : @AnantoPatrick
Facebook : Patrick Ananta
No comments:
Post a Comment