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. Bahasa pemrograman ini gratis dan open source, dan menjanjikan untuk membuat coding untuk Android semakin menyenangkan.
Pada artikel sebelumnya, Anda belajar tentang kelas dan objek di Kotlin. Dalam tutorial ini, kita akan terus belajar lebih banyak tentang properti dan juga melihat jenis kelas lanjutan di Kotlin dengan mengeksplorasi hal berikut:
- Late-Initialized Properti
- Inline Properti
- extension properti
- data, enum, nested, dan sealed class
1. ILate-Initialized Properti
Kita bisa mendeklarasikan properti non-null di Kotlin sebagai late-initialized. Ini berarti bahwa properti non-null tidak akan diinisialisasi pada waktu deklarasi dengan inisialisasi nilai sebenarnya tidak akan terjadi melalui konstruktor apapun namun sebaliknya, akan diinisialisasi di akhir dengan metode atau injeksi dependensi.
Mari kita lihat sebuah contoh untuk memahami pengubah properti unik ini.
class Presenter { private var repository: Repository? = null fun initRepository(repo: Repository): Unit { this.repository = repo } } class Repository { fun saveAmount(amount: Double) {} }
Dalam kode di atas, kami mendeklarasikan properti Repository
nihil yang dapat berubah-ubah yang merupakan jenis Repository
- di dalam class Presenter
- dan kami kemudian menginisialisasi properti ini menjadi nol selama deklarasi. kita memiliki fungsi initRepository()
di dalam kelas Presenter
yang menginisiasi ulang properti ini nanti dengan aktual instance Repository
. Perlu diingat bahwa properti ini juga bisa diisi nilai menggunakan injektor dependensi seperti pisau.
Sekarang, kita panggil fungsi atau sifat dalam hal ini properti repository
, kita harus melakukan pengecekan null atau menggunakan safe call operatoro. Mengapa? Karena properti repository
merupakan nullable bertipe (Repository?
). (Jika Anda butuh penjelasan tentang nullability pada Kotlin, silahkan kunjungi Nullability, Loops, and Conditions).
// Inside Presenter class fun save(amount: Double) { repository?.saveAmount(amount) }
Untuk menghindari melakukan null check setiap waktu kita perlu untuk memanggil fungsi dari properti, kita bisa menandai properti tersebut dengan modifier lateinit
— Ini berarti kita telah mendeklarasikan properti tersebut (yang mana merupakan instance dari kelas lain) sebagai late-initialized (artinya property akan diinisialisasikan nanti).
class Presenter { private lateinit var repository: Repository //... }
Sekarang, selama kita menunggu sampai properti telah diberi nilai, kita dapat mengakses fungsi dari properti tanpa melakukan null check. Inisialisasi properti bisa terjadi baik dalam metode setter atau melalui injeksi dependensi.
repository.saveAmount(amount)
Perlu dicatat bahwa jika kita ingin mencoba mengakses method dari properti sebelum itu terinisialisasi, kita akan mendapat pesan kotlin.UninitializedPropertyAccessException
bukannya NullPointerException
. Dalam hal ini, pesan akan menjadi "lateinit property repository has not been initialized".
Perhatikan juga pembatasan berikut ditempatkan saat menunda inisialisasi properti dengan lateinit
:
- Ini dapat berubah (deklarasi dengan
var
). - Tipe properti tidak bisa menjadi tipe primitif —contoh,
Int
,Double
,Float
, dan lainnya. - Properti tidak bisa punya getter atau setter kustom.
2. Inline Properties
Dalam Fungsi Lanjutan, Saya menjelaskan tentang modifier inline
untuk fungsi high-order — ini membantu mengoptimasi fungsi high-order yang menerima lambda sebagai parameter.
Di Kotlin, kita juga dapat menggunakan modifier inline
pada properti. Menggunakan modifier ini akan mengoptimalkan akses ke properti.
Mari lihat contohnya
class Student { val nickName: String get() { println("Nick name retrieved") return "koloCoder" } } fun main(args: Array<String>) { val student = Student() print(student.nickName) }
Pada kode di atas, kita punya sebuah properti normal, nickName
, yang tidak memiliki modifier inline
. Jika kita mendekompilasi snippet kode, menggunakan fitur Show Kotlin Bytecode (jika di IntelliJ IDEA or Android Studio, menggunakan Tools > Kotlin > Show Kotlin Bytecode), kita akan melihat java code berikut:
public final class Student { @NotNull public final String getNickName() { String var1 = "Nick name retrieved"; System.out.println(var1); return "koloCoder"; } } public final class InlineFunctionKt { public static final void main(@NotNull String[] args) { Intrinsics.checkParameterIsNotNull(args, "args"); Student student = new Student(); String var2 = student.getNickName(); System.out.print(var2); } }
Dalam kode Java yang dihasilkan di atas (beberapa elemen kode yang dihasilkan dihapus karena singkatnya maksudnya), Anda dapat melihatnya di dalam metode main()
compiler membuat sebuah objek Student
, memanggil method getNickName()
, dan selanjutnya menampilkan nilai.
Sekarang tentukan properti sebagai inline
Sebagai gantinya, dan bandingkan bytecode yang dihasilkan.
// ... inline val nickName: String // ...
Kita tinggal memasukkan modifier inline
sebelum variabel modifier: var
or val
. Berikut ini bytecode yang telah dihasilkan pada inline property:
// ... public static final void main(@NotNull String[] args) { Intrinsics.checkParameterIsNotNull(args, "args"); Student student = new Student(); String var3 = "Nick name retrieved"; System.out.println(var3); String var2 = "koloCoder"; System.out.print(var2); } // ...
Lagi-lagi, beberapa kode terhapus, tetapi hal penting yang perlu dicatat adalah method main()
. Compiler telah menyalin isi fungsi properti get() dan menaruhnya ke dalam call site (mekanisme ini mirip dengan inline functions).
Kode kita telah dioptimalkan karena tidak perlu membuat objek dan memanggil metode pengambil properti. Tapi, seperti yang dibahas di posting fungsi inline, kita akan memiliki bytecode lebih besar dari sebelumnya - jadi gunakan dengan hati-hati.
Perhatikan juga bahwa mekanisme ini akan bekerja untuk properti yang tidak memiliki backing field (ingat, backing field hanya bidang yang digunakan oleh properti saat Anda ingin memodifikasi atau menggunakan data bidang itu).
3. Extension Properties
Pada Advanced Functions Saya juga membahas extension functions yang memberi kita kemampuan untuk mengextend sebuah kelas dengan fungsi baru tanpa mewariskan sifat dari kelas tersebut. Kotlin juga menyediakan mekanisme serupa untuk properti, yang disebut extension properties.
val String.upperCaseFirstLetter: String get() = this.substring(0, 1).toUpperCase().plus(this.substring(1))
Pada Advanced Functions post Kita mendefinisikan sebuah extension function uppercaseFirstLetter()
dengan tipe receiver String
. Disini, kita mengkonversi itu ke dalam top-level extension property. perhatikan bahwa Anda harus mendefinisikan sebuah getter method pada properti agar berhasil.
Jadi dengan pengetahuan baru tentang properti ekstensi ini, Anda akan tahu bahwa jika Anda menginginkan kelas harus memiliki properti yang tidak tersedia, Anda bebas untuk membuat properti ekstensi dari kelas itu.
4. Data Classes
Mari kita mulai dengan kelas Java yang khas atau POJO (Plain Old Java Object).
public class BlogPost { private final String title; private final URI url; private final String description; private final Date publishDate; //.. constructor not included for brevity's sake @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BlogPost blogPost = (BlogPost) o; if (title != null ? !title.equals(blogPost.title) : blogPost.title != null) return false; if (url != null ? !url.equals(blogPost.url) : blogPost.url != null) return false; if (description != null ? !description.equals(blogPost.description) : blogPost.description != null) return false; return publishDate != null ? publishDate.equals(blogPost.publishDate) : blogPost.publishDate == null; } @Override public int hashCode() { int result = title != null ? title.hashCode() : 0; result = 31 * result + (url != null ? url.hashCode() : 0); result = 31 * result + (description != null ? description.hashCode() : 0); result = 31 * result + (publishDate != null ? publishDate.hashCode() : 0); return result; } @Override public String toString() { return "BlogPost{" + "title='" + title + '\'' + ", url=" + url + ", description='" + description + '\'' + ", publishDate=" + publishDate + '}'; } //.. setters and getters also ignored for brevity's sake }
Seperti yang terlihat, kita perlu membuat kode pada kelas properti secara eksplisit: getter dan setter seperti hashcode
, equals
, dan toString
methods (meskipun IntelliJ IDEA, Android Studio, atau library AutoValue dapat membantu kita menghasilkan itu). Kita bisa lihat kebanyakan kode pada di lapisan data dari proyek Java yang khas (Saya menghilangkan field accessors dan constuctorI removed the field accessors and constructor untuk mempersingkat).
Hal bagus yaitu tim Kotlin menyediakan kita dengan modifier data
untuk kelas untuk mengeliminasi penulisan boilerplate.
Mari sekarang tuliskan kode sebelumnya di Kotlin.
data class BlogPost(var title: String, var url: URI, var description: String, var publishDate: Date)
Menakjubkan! Kita baru saja menentukan modifier data
sebelum kata kunci class
untuk membuat sebuat kelas data seperti apa yang kita telah lakukan pada class diatas BlogPost
. Sekarang equals
, hashcode
, toString
, copy
, dan beberapa metode komponen akan dibuat untuk kita. Perhatikan bahwa data kelas dapat memperpanjang kelas lainnya (ini adalah fitur baru Kotlin 1.1).
Metode equals
Metode ini membandingkan dua objek untuk persamaan, dan mengembalikan nilai true jika sama atau salah. Dengan kata lain, membandingkan jika dua instance kelas berisi data yang sama.
student.equals(student3) // using the == in Kotlin student == student3 // same as using equals()
Di Kotlin, menggunakan operator persamaan ==
akan memanggil methode quals
.
Metode hashCode
Metode ini mengembalikan nilai integer yang digunakan untuk penyimpanan cepat dan pengambilan data yang tersimpan dalam struktur data koleksi berbasis hash, misalnya di HashMap
dan collection types HashSet
.
Metode toString
Metode ini menghasilkan representasi String
dari sebuah objek.
data class Person(var firstName: String, var lastName: String) val person = Person("Chike", "Mgbemena") println(person) // prints "Person(firstName=Chike, lastName=Mgbemena)"
Dengan hanya memanggil instance kelas, kita mendapatkan sebuah objek string kembali kepada kita-Kotlin memanggil objek itu toString()
untuk kita. Tapi jika kita tidak meletakkan kata kunci data
, lihat apa representasi string objek kita:
com.chike.kotlin.classes.Person@2f0e140b
Jauh Lebih Informatif!
Method copy
Metode ini memungkinkan kita membuat instance baru dari sebuah objek dengan semua nilai properti yang sama. Dengan kata lain, itu menciptakan salinan objek.
val person1 = Person("Chike", "Mgbemena") println(person1) // Person(firstName=Chike, lastName=Mgbemena) val person2 = person1.copy() println(person2) // Person(firstName=Chike, lastName=Mgbemena)
Hal bagus tentang method copy
pada Kotlin adalah kemampuan untuk mengubah properti selama penyalinan.
val person3 = person1.copy(lastName = "Onu") println(person3) //Person3(firstName=Chike, lastName=Onu)
Jika Kamu Java coder, method ini mirip dengan method clone()
yang telah kamu ketahui. Tapi metode copy
Kotlin mempunyai banyak fitur unggulan.
Destructive Declaration
Pada class Person
, kita juga telah mempunyai dua auto-generated method oleh compiler karena keyword data
ditempatkan pada kelas. Dua method itu merupakan These two methods diawali dengan "komponen", kemudian diikuti oleh sejumlah sufiks: component1()
, component2()
. Masing-masing metode ini mewakili sifat individu dari jenis ini. Perhatikan bahwa akhiran sesuai dengan urutan properti yang dinyatakan dalam konstruktor utama.
Jadi, di contoh kita panggil component1()
akan menampilkan first name, dan memanggil component2()
akan menampilkan last name.
println(person3.component1()) // Chike println(person3.component2()) // Onu
Memanggil properti menggunakan gaya ini sulit dimengerti dan dibaca, karena begitu memanggil nama properti secara eksplisit jauh lebih baik. Namun, properti yang dibuat secara implisit ini memiliki tujuan yang sangat berguna: mereka membiarkan kita melakukan deklarasi destrukturisasi, di mana kita dapat menetapkan setiap komponen ke variabel lokal.
val (firstName, lastName) = Person("Angelina", "Jolie") println(firstName + " " + lastName) // Angelina Jolie
Apa yang telah kita lakukan di sini adalah langsung menetapkan properti pertama dan kedua (firstName
dan lastName
) dari Person
tipe variabel firstName
dan lastName
masing2. Saya juga membahas mekanisme ini yang dikenal dengan destructuring declaration di bagian terakhir Packages and Basic Functions post.
5. Nested Classes
Pada More Fun With Functions post, Saya katakan bahwa Kotlin memiliki dukungan untuk fungsi lokal atau nested — fungsi yang dinyatakan di dalam fungsi lain. Nah, Kotlin juga mendukung kelas bersarang — kelas yang dibuat di kelas lain.
class OuterClass { class NestedClass { fun nestedClassFunc() { } } }
Kami bahkan memanggil fungsi publik kelas nested seperti yang terlihat di bawah ini-kelas bersarang di Kotlin setara dengan sebua static
kelas bersarang di Java. Perhatikan bahwa kelas bersarang tidak dapat menyimpan referensi ke kelas luarnya.
val nestedClass = OuterClass.NestedClass() nestedClass.nestedClassFunc()
We're also free to set the nested class as private — this means we can only create an instance of the NestedClass
within the scope of the OuterClass
.
Inner Class
Inner classes, Di sisi lain, bisa merujuk Outter Classes yang dideklarasikannya. Untuk membuat Inner
Class, kita tempatkan keywordinner sebelum keyword class
pada nested class.
class OuterClass() { val oCPropt: String = "Yo" inner class InnerClass { fun innerClassFunc() { val outerClass = this@OuterClass print(outerClass.oCPropt) // prints "Yo" } } }
Disini kita mereferensi OuterClass
dari InnerClass
menggunakan this@OuterClass
.
6. Enum Classes
Jenis enum menyatakan satu set konstanta yang ditunjukkan oleh pengenal. Kelas khusus ini dibuat oleh kata kunci enum
yang ditentukan sebelum kata kunci class
.
enum class Country { NIGERIA, GHANA, CANADA }
Untuk mengambil nilai enum berdasarkan namanya (seperti di Java), kita dapat melakukan ini:
Country.valueOf("NIGERIA")
atau kita bisa menggunakan helper method Kotlin enumValueOf<T>()
untuk mengakses constants melalui cara biasa:
enumValueOf<Country>("NIGERIA")
Juga, kita bisa mendapatkan semua nilai (seperti untuk Java enum) seperti ini:
Country.values()
Akhirnya, kita bisa menggunakan helper method Kotlin enumValueOf<T>()
untuk mendapatkan semua entri enum secara generik:
enumValues<Country>()
Ini mengembalikan sebuah array yang berisi entri enum.
Enum Constructors
Sama seperti kelas normal, tipe enum
dapat memiliki konstruktor sendiri dengan sifat yang terkait dengan setiap konstanta enum.
enum class Country(val callingCode: Int) { NIGERIA (234), USA (1), GHANA (233) }
Pada enum tipe primary constructor Country
, kita mendefinisikan properti yang tidak berubah callingCodes
untuk setiap konstanta enum. Dalam masing-masing konstanta, kami melewati sebuah argumen ke konstruktor.
Kita kemudian bisa mengakses properti konstanta seperti ini:
val country = Country.NIGERIA print(country.callingCode) // 234
7. Sealed Classes
Sealed Class di Kotlin adalah kelas abstrak (Anda tidak pernah bermaksud membuat objek darinya) yang dapat diperluas kelas lain. Subclass ini didefinisikan di dalam tubuh kelas yang disegel — dalam file yang sama. Karena semua subclass ini didefinisikan di dalam tubuh kelas yang disegel, kita dapat mengetahui semua subclass yang mungkin dengan hanya melihat file.
Lihat contoh berikut.
// shape.kt sealed class Shape class Circle : Shape() class Triangle : Shape() class Rectangle: Shape()
Untuk mendeklarasikan sebuah class sebagai sealed
, kita masukkan modifier sealed sebelum modifier class
di header deklarasi kelas — dalam kasus kita, kita menyatakan class Shape
sebagai sealed
. Sealed class tidak lengkap tanpa subkelasnya — sama seperti kelas abstrak yang khas — jadi kita harus mendeklarasikan subclass individual di dalam file yang sama (shape.kt pada kasus ini). Perhatikan bahwa Anda tidak dapat menentukan subkelas dari kelas yang disegel dari file lain.
Dalam kode di atas, kami telah menentukan bahwa kelas Shape
hanya bisa diperpanjang oleh kelas Circle
, Triangle
, dan Rectangle
.
Sealed classes pada Kotlin memiliki aturan tambahan:
- Kita bisa menambahkan modifier
abstract
ke sealed class, tapi ini berlebihan karena kelas tertutup abstrak secara default. - Sealed classes tidak bisa punya modifier
open
ataufinal
. - kita juga bebas untuk mendeklarasikan kelas data dan objek sebagai subclass ke kelas yang disegel (mereka masih perlu dideklarasikan di file yang sama).
- Kelas yang tertutup tidak diizinkan untuk memiliki konstruktor publik — konstruktor mereka bersifat pribadi secara default.
Kelas yang memperpanjang subclass dari kelas yang disegel dapat ditempatkan baik dalam file yang sama atau file lain. Subclass kelas yang disegel harus ditandai dengan modifier open
(Anda akan belajar lebih banyak tentang warisan di Kotlin di posting berikutnya).
// employee.kt sealed class Employee open class Artist : Employee() // musician.kt class Musician : Artist()
Kelas yang disegel dan subclassnya sangat berguna dalam ekspresi when
. contoh:
fun whatIsIt(shape: Shape) = when (shape) { is Circle -> println("A circle") is Triangle -> println("A triangle") is Rectangle -> println("A rectangle") }
Disini compiler pintar memastikan kita menutup semua kemungkinan kasus when
. Itu berarti tidak perlu menambahkan kata else
.
Jika kita melakukan hal berikut sebagai gantinya:
fun whatIsIt(shape: Shape) = when (shape) { is Circle -> println("A circle") is Triangle -> println("A triangle") }
Kode tidak akan dikompilasi, karena kita belum memasukkan semua kemungkinan kasus. kita dapat pesan kesalahan berikut:
Kotlin: 'when' expression must be exhaustive, add necessary 'is Rectangle' branch or 'else' branch instead.
Jadi kita bisa memasukkan case is Rectangle
atau kata else
untuk menyempurnakan ekspresi when
.
Kesimpulan
Dalam tutorial ini, Anda belajar lebih banyak tentang kelas di Kotlin. kita membahas hal berikut tentang properti kelas:
- late initialization
- inline properties
- extension properties
Juga, Anda belajar tentang beberapa kelas yang keren dan canggih seperti data, enum, nested, dan kelas tertutup. Pada tutorial berikutnya di Kotlin From Scratch, Anda akan diperkenalkan ke antarmuka dan pewarisan di Kotlin. Sampai jumpa lagi!
Untuk mempelajari lebih lanjut tentang bahasa Kotlin, saya sarankan untuk mengunjungi Kotlin documentation. Atau lihat beberapa posting pengembangan aplikasi Android kami yang lain di sini tentang Envato Tuts!
- Android SDKConcurrency di RxJava 2Chike Mgbemena
- Android SDKMengirim Data dengan Retrofit 2 HTTP Client untuk AndroidChike Mgbemena
- Android SDKJawa vs Kotlin: Haruskah Anda menggunakan Kotlin untuk Development Android?Jessica Thornsby
- Android SDKCara membuat aplikasi Chat Android menggunakan FirebaseAshraff Hathibelagal