Pengenalan Kotlin
Pengenalan Kotlin
Dukungan tools untuk Kotlin , sangat kuat. Kita bisa dengan mudah
menggunakan Kotlin pada IDE seperti IntelliJ IDEA, Android
Studio, Eclipse, dan NetBeans. Anda pun bisa menggunakan perintah
terminal untuk mengkompilasi dan menjalankan Kotlin. Begitu pula
untuk build tools. Pada JVM kita bisa
menggunakan Gradle, Maven, Ant, atau Kobalt. Tersedia juga
beberapa build tools yang menargetkan JavaScript.
Pada sub-modul ini kita akan mencoba mengenal Kotlin secara lebih
mendalam. Harapannya, sebelum mempelajari komponen-komponen
pada Kotlin secara spesifik, kita semua bisa memahami untuk apa saja
Kotlin bisa digunakan, apa saja kelebihan dan kekurangannya,
karakteristiknya, dan juga seperti apa ekosistem Kotlin di dunia
pengembangan aplikasi.
Multiparadigm
Object-oriented Programming
Functional Programming
Multiplatform
Common Module
Modul ini berisi kode yang tidak spesifik ke platform apa pun.
Kita bisa menempatkan komponen-komponen yang bisa
digunakan oleh semua modul pada modul ini.
Platform Module
Pada modul ini kita bisa menambahkan komponen tertentu yang
spesifik untuk satu platform. Biasanya modul ini merupakan
implementasi dari common module.
Regular Module
Merupakan modul umum yang menargetkan platform tertentu.
Modul ini bisa dependen atau pun menjadi dependensi
dari platform module.
Kotlin pun telah menyiapkan beberapa library khusus untuk
mendukung proyek multiplatform, di antaranya
adalah HTTP, serialization, dan coroutines. Semua library tersebut bisa
kita terapkan pada common module dan kemudian diakses oleh
modul lainnya. Anda pun tetap bisa menggunakan Kotlin standard
library pada semua modul. Tentunya ini akan sangat membantu
memudahkan proses pengembangan aplikasi.
JetBrains juga memiliki beberapa contoh proyek yang bisa kita pelajari
untuk menerapkan Kotlin Multiplatform:
KotlinConf App
KotlinConf Spinner App
Expressiveness
Fitur-fitur pada Kotlin seperti type-safe builder dan delegated
properties akan membantu membangun abstraksi yang kuat dan
mudah digunakan.
Scalability
Dukungan Kotlin untuk coroutines akan membantu kita.
Khususnya dalam membangun aplikasi server-side dengan skala
yang besar, namun menggunakan perangkat yang sederhana.
Interoperability
Kotlin sepenuhnya kompatibel dengan semua framework Java. Ini
memungkinkan Anda tetap menggunakan teknologi yang sudah
ada dan mulai menggunakan bahasa yang lebih modern.
Migration
Kotlin mendukung proses migrasi secara bertahap, dari Java ke
Kotlin. Anda dapat mulai menulis kode baru dengan Kotlin tanpa
memodifikasi kode Java yang sudah ada.
Tooling
Selain dukungan IDE yang powerful, Kotlin menawarkan
beberapa plugin untuk framework spesifik seperti Spring.
Tersedia juga berbagai macam framework yang bisa Anda gunakan
untuk mempermudah pengembangan aplikasi server-side seperti:
1. Spring
Spring merupakan sebuah framework yang sangat terkenal di
Java. Spring bisa digunakan pada Kotlin untuk komunikasi ke API
dengan lebih ringkas. Tersedia juga Spring Initializr yang
memungkinkan kita untuk membuat proyek Spring baru dengan
Kotlin.
2. Vert.x
Merupakan sebuah framework untuk membuat reactive Web app
di JVM. Anda bisa melihat repository-nya
di https://github.com/vert-x3/vertx-lang-kotlin .
3. Ktor
Ktor adalah sebuah framework yang dikembangkan oleh JetBrains
untuk membuat aplikasi Web di Kotlin. Ktor memanfaatkan
coroutine untuk skalabilitas yang tinggi dan menawarkan API
yang mudah digunakan.
4. Kotlinx.html
Merupakan sebuah DSL yang dapat digunakan untuk membuat
HTML di aplikasi Web. Kotlinx.html dapat digunakan sebagai
alternatif untuk sistem templating tradisional seperti JSP dan
FreeMarker.
5. Exposed
Sebuah framework SQL yang menyediakan kumpulan DSL yang
mudah dibaca untuk menggambarkan struktur database SQL
dan melakukan kueri sepenuhnya dengan Kotlin.
Jelas terdapat berbagai kemudahan yang ditawarkan dan juga
dukungan framework yang kuat. Para developer tak perlu ragu lagi
dalam mencoba menerapkan Kotlin sebagai bahasa pemrograman
untuk mengembangkan aplikasi server-side. Anda pun bisa mulai
mencobanya dengan mengikuti beberapa dokumentasi berikut.
Compatibility
Kotlin sepenuhnya kompatibel dengan JDK 6. Ini memastikan
bahwa aplikasi yang dibangun dengan Kotlin dapat berjalan pada
perangkat Android yang lebih lama tanpa ada masalah. Android
Studio pun mendukung penuh pengembangan dengan bahasa
Kotlin.
Performance
Dengan struktur bytecode yang sama dengan Java, aplikasi yang
dibangun dengan Kotlin dapat berjalan setara dengan aplikasi
yang dibangun dengan Java. Terdapat juga fitur seperti inline
function pada Kotlin yang membuat kode yang dituliskan
dengan lambda bisa berjalan lebih cepat dibandingkan kode
yang sama dan dituliskan dengan Java.
Interoperability
Anda dapat menggunakan bahasa Kotlin bersamaan dengan
bahasa Java, tanpa harus memigrasikan semua kode lama Anda
ke Java. Sehingga, Anda dapat memanggil kode Java dari Kotlin
dan sebaliknya. Inilah alasan yang menyebabkan Kotlin menjadi
cepat diterima oleh developer.
Compilation Time
Kotlin mendukung kompilasi inkremental yang efisien. Oleh
karena itu, proses build biasanya sama atau lebih cepat
dibandingkan dengan Java.
Easy Learning
Kotlin sangat mudah untuk dikuasai, terlebih jika Anda
sebelumnya adalah Java Developer.
Big Community
Kotlin memiliki banyak dukungan dan kontribusi dari komunitas,
yang mana pertumbuhannya sangat kencang di seluruh dunia.
Lebih dari 95% aplikasi terbaik di Play Store menggunakan Kotlin.
Perkembangan Kotlin pada Android pun bisa dibilang sangat cepat.
Bahkan pada acara Google I/O 2019 lalu, Google
mengumumkan Kotlin First!, yaitu menetapkan Kotlin sebagai bahasa
pemrograman nomor 1 (satu) untuk Android. Hampir semua update
pada Android saat ini sudah menggunakan Kotlin pada
dokumentasinya. Tim Android juga merilis Android Jetpack yang
merupakan sekumpulan library yang dapat digunakan untuk
memanfaatkan fitur bahasa Kotlin dengan lebih advanced. Dengan
kematangan Kotlin, banyak perusahaan siap menggunakan Kotlin
sebagai bahasa pemrograman untuk membangun aplikasi Android.
1. Ringkas (Concise)
Selain mudah dipelajari, bahasa pemrograman baru yang satu ini
juga mudah untuk dituliskan. Sintaksisnya pun mudah dibaca
dan bisa dibilang lebih “manusiawi.” Mungkin karena penamaan
fungsi di dalamnya yang mirip dengan bahasa manusia sehari-
hari. Kotlin memungkinkan kita untuk mengurangi jumlah
penulisan kode boilerplate. Maka jangan heran jika kita sering
mendengar istilah “nicer Java”.
2. Dapat dioperasikan secara bersilangan (Interoperable)
Apakah Anda seorang Java developer yang ingin berpindah ke
Kotlin? Jangan khawatir, Kotlin dan Java sama-sama berjalan di
atas JVM. Alhasil, keduanya bisa dijalankan bersamaan dalam 1
(satu) proyek. Tentunya ini sangat menguntungkan. Kita tidak
perlu menuliskan ulang kode Java yang sudah ada. Anda cukup
menuliskan kode baru dengan Kotlin. Menariknya, selain bisa
dijalankan bersamaan, fungsi yang ada pada kedua bahasa
tersebut juga bisa saling diakses. Java bisa mengakses fungsi
yang ada pada Kotlin. Sebaliknya, Kotlin juga bisa mengakses
fungsi yang ada pada Java.
3. Dukungan tools yang memadai (Tool-friendly)
Membahas soal produktivitas, tentu tak jauh dari
dukungan tools yang diberikan. Saat ini banyak IDE yang
mendukung Kotlin. Tersedia juga https://play.kotlinlang.org/ yang
memungkinkan Anda mencoba Kotlin secara online. Kita pun
tetap bisa menggunakan command line atau terminal. Kita akan
mempelajari tentang IDE dan tools lainnya pada modul terpisah.
Dengan keunggulan-keunggulan Kotlin tersebut, bisa kita simpulkan
bahwa Kotlin merupakan bahasa pemrograman yang wajib kita
pelajari. Bagi seseorang yang baru mengenal pemrograman,
mempelajari Kotlin bisa menjadi investasi yang baik.
Dukungan multiplatform memungkinkan kita untuk merambah ke
berbagai platform. Lebih lanjut, konsep OOP dan FP bisa menjadi
modal utama seorang programmer untuk mempelajari bahasa
pemrograman lain di kemudian hari.
Semakin ringkas sebuah kode, maka semakin cepat pula untuk kita
pahami. Selain ringkas, faktor lain seperti penamaan fungsi juga akan
sangat berpengaruh. Kotlin memiliki fungsi-fungsi bawaan yang
namanya mudah diingat. Bahkan pilihan keyword yang terkesan sangat
sederhana. Mari kita perhatikan perbandingan antara Kotlin dan Java
berikut:
Java:
Kotlin:
“Hal apa yang pertama kali Anda lihat ketika melihat 2 (dua) kode
di atas?”.
Ya benar, itu adalah salah satu ciri dari Kotlin. Sederhana, tapi tak
jarang programmer dibuat pusing karena lupa
menambahkan semicolon di akhir kode ketika ngoding dengan Java.
Kode di atas memiliki kegunaan yang sama namun dituliskan dengan
bahasa pemrograman yang berbeda. Terlihat dengan sangat jelas
bahwa kode yang dituliskan dengan Kotlin lebih ringkas dan lebih
mudah dipahami, bukan? Nah, itu belum seberapa. Pada akademi ini
Anda akan melihat banyak contoh kode yang menunjukan bahwa
Kotlin adalah bahasa yang sangat ringkas.
Pragmatic
Selain ringkas ditulis, hal lain yang membuat Kotlin bisa dikatakan
pragmatis adalah dukungan tools yang sangat membantu proses
penulisan kode. JetBrains menambahkan dukungan Kotlin pada IntelliJ
IDEA beserta plugin-plugin yang disesuaikan dengan setiap fitur yang
ada pada Kotlin.
Statically Typed
Selain itu, Kotlin juga mendukung function type, yang nanti akan kita
pelajari pada sub-modul functional programming.
Ekosistem Kotlin
Berbicara mengenai ekosistem, di Indonesia sendiri Kotlin mulai ramai
digunakan sejak tahun 2017. Pada tahun itu, Kotlin ditetapkan sebagai
bahasa pemrograman resmi pada salah satu platform yang juga
sangat terkenal, yaitu Android. Walaupun sebenarnya sebelum tahun
2017 juga ada developer yang sudah mulai menuliskan kodenya
dengan Kotlin.
Saat ini, banyak aplikasi yang dikembangkan dengan Kotlin. Mulai dari
startup yang baru mulai dirintis sampai perusahaan yang sudah
memiliki title Unicorn seperti GO-JEK, Tokopedia, dan Bukalapak.
https://developer.android.com/kotlin
Berikut adalah beberapa kanal komunitas yang bisa Anda ikuti untuk
mendapatkan update rutin seputar Kotlin.
Kotlin Indonesia
Kotlinlang
Antonioleiva.com
Kotlin Weekly
Kotlin.link
The Daily Kotlin
Talking Kotlin
o Common Module
Modul ini berisi kode yang tidak spesifik ke platform apa
pun. Kita bisa menempatkan komponen-komponen yang
bisa digunakan oleh semua modul pada modul ini.
o Platform Module
Pada modul ini kita bisa menambahkan komponen tertentu
yang spesifik untuk satu platform. Biasanya modul ini
merupakan implementasi dari common module.
o Regular Module
Merupakan modul umum yang menargetkan platform
tertentu. Modul ini bisa dependen atau pun menjadi
dependensi dari platform module.
5. Kotlin mendukung dengan baik dan memiliki beberapa kelebihan
dalam mengembangkan aplikasi Android seperti di bawah ini:
o Compatibility
Kotlin sepenuhnya kompatibel dengan JDK 6. Ini
memastikan bahwa aplikasi yang dibangun dengan Kotlin
dapat berjalan pada perangkat Android yang lebih lama
tanpa ada masalah. Android Studio pun mendukung penuh
pengembangan dengan bahasa Kotlin.
o Performance
Dengan struktur bytecode yang sama dengan Java, aplikasi
yang dibangun dengan Kotlin dapat berjalan setara dengan
aplikasi yang dibangun dengan Java. Terdapat juga fitur
seperti inline function pada Kotlin yang membuat kode
yang dituliskan dengan lambda bisa berjalan lebih cepat
dibandingkan kode yang sama dan dituliskan dengan Java.
o Interoperability
Anda dapat menggunakan bahasa Kotlin bersamaan
dengan bahasa Java, tanpa harus memigrasikan semua
kode lama Anda ke Kotlin. Sehingga Anda dapat memanggil
kode Java dari Kotlin dan sebaliknya. Inilah alasan yang
menyebabkan Kotlin menjadi cepat diterima oleh
developer.
o Compilation Time
Kotlin mendukung kompilasi inkremental yang efisien. Oleh
karena itu, proses build biasanya sama atau lebih cepat
dibandingkan dengan Java.
6. Perkembangan Kotlin pada Android pun bisa dibilang sangat
cepat. Bahkan pada acara Google I/O 2019 lalu, Google
mengumumkan Kotlin First!, yaitu menetapkan Kotlin sebagai
bahasa pemrograman nomor 1 (satu) untuk Android. Hampir
semua update pada Android saat ini sudah menggunakan Kotlin
pada dokumentasinya.
7. Berikut ini adalah beberapa karakteristik dari bahasa Kotlin
JDK, JRE dan JVM sendiri terlihat sama karena ketiganya merupakan inti
dari bahasa pemrograman Java. Meski terlihat sama, masing-masing
dari ketiganya, punya peran sendiri-sendiri. JDK (Java Development
Kit) adalah sebuah perangkat lunak yang menyediakan
beberapa tools untuk pengembangan dan berkas binary yang
diperlukan untuk proses kompilasi dari kode Java ke bytecode.
Pada dasarnya, setiap JDK yang bisa kita gunakan memiliki basis
OpenJDK dan bersifat open-source. Perbedaannya adalah cara JDK
tersebut didistribusikan. Contoh distribusinya bisa dari Oracle
(OracleJDK), OpenJDK Distribution atau Azul Zulu JDK.
Pada kelas ini, kita akan menggunakan JDK yang didistribusikan oleh
OpenJDK Distribution karena bisa digunakan secara gratis dengan
lisensi personal. Nah untuk JRE, kita tidak perlu melakukan instalasi
secara terpisah karena sudah terdapat di dalam paket instalasi
OpenJDK.
Build Tools
Selanjutnya adalah build tools, perangkat lunak yang akan kita gunakan
untuk membantu mengotomatisasi proses. Seperti misalnya
pemaketan dari proyek yang kita akan kembangkan. Selain
kompiler command line dan IntelliJ IDEA, Anda juga dapat
menggunakan Ant, Maven, dan Gradle sebagai build tools-nya. Dari
ketiga build tools tersebut, Gradle-lah yang paling sering digunakan.
Pasalnya, ia cukup fleksibel dalam membantu proses kompilasi.
Dari semua IDE tersebut, IntelliJ IDEA dan Android Studio-lah yang
paling direkomendasikan. Anda bisa menggunakan IntelliJ IDEA untuk
pengembangan aplikasi secara umum dan Android Studio untuk
pengembangan aplikasi Android.
.
Pada akademi ini, kita akan fokus menggunakan IntelliJ IDEA. IntelliJ
IDEA dikembangkan oleh pengembang yang sama dengan Kotlin, yaitu
JetBrains. Tentunya ada kompatibilitas yang lebih antara keduanya.
Bahkan, JetBrains juga menyediakan tutorial khusus untuk memulai
Kotlin menggunakan IntelliJ IDEA. Anda bisa membacanya di tautan ini.
Dengan dukungan fitur yang mumpuni, IntelliJ IDEA dapat membantu
kita menyelesaikan program yang sedang kita kembangkan dengan
cepat.
Intellij IDEA memiliki dua versi yang dapat kita gunakan untuk
pengembangan aplikasi, yaitu versi Ultimate dan Community. Versi
Ultimate ditujukan untuk pengembangan aplikasi lebih lanjut. Pada
akademi ini, kita akan menggunakan versi Community untuk belajar
Kotlin.
Dalam gambar di atas, kita bisa tahu bahwa lokasi JDK akan diinstal
pada folder C:\Program Files\Zulu\zulu-8. Jika telah Anda catat,
lanjutkan kembali proses instalasi dengan mengikuti panduan yang
tampil hingga selesai.
Konfigurasi JAVA_HOME
Catatan: Untuk menambahkan di level System Variable, gunakanlah versi admin (bawah). Jika versi biasa (atas), Anda
Setelah
jendela baru terbuka, Klik tombol New kemudian tambahkan lokasi
dari berkas distribusi Gradle seperti contoh berikut.
Catatan: Untuk pengguna Windows 7, perintah di atas akan sedikit berbeda. Tapi tidak perlu khawatir, caranya cukup
tampil seperti di bawah ini:
Tambahkan lokasi paket distribusi Gradle pada baris terakhir yang di awali dengan karakter ; (titik koma). Kurang
setelah ditambahkan.
Setelah selesai, klik OK pada jendela yang tampil dan
jendela Environment Variable. Untuk memastikan apakah gradle
sudah terinstall dengan baik. Anda bisa menjalankan perintah gradle -
v pada command prompt seperti berikut.
Windows
macOS
Linux
Pada dasarnya jika sebelumnya komputer kita sudah terinstal JDK, kita
tidak perlu melakukan konfigurasi pada Intellij IDEA. Mengapa
demikian? JDK akan secara otomatis terdeteksi sehingga Anda bisa
langsung menggunakannya untuk membuat proyek baru.
Untuk mengenal IntelliJ IDEA lebih lanjut, Anda bisa membaca blog
berikut: Berkenalan Dengan IntelliJ IDEA
Program Pertama Kotlin
Jika semua tools sudah siap, kini Anda bisa mulai mencoba untuk
membuat dan menjalankan program dengan Kotlin. Seperti yang
sudah disampaikan, Kotlin memiliki dukungan tools yang memadai.
Ketika ingin membuat sebuah program dengan Kotlin, Anda bisa
memilih berbagai macam tools mulai dari yang paling dasar hingga
tingkat lanjut.
Sebelum membuat project, terlebih dahulu buat folder baru yang akan
digunakan sebagai folder project yang nantinya akan kita buat. Setelah
selesai, silakan buka terminal atau command prompt dari dalam
folder tersebut.
Untuk Anda yang menggunakan sistem operasi Windows, gunakan pintasan dengan menulisakan cmd pada search ba
membuka Command Prompt dari dalam folder project seperti berikut:
Mari kita pelajari satu per satu dari masing-masing berkas tersebut.
Gradle Wrapper
1. distributionBase=GRADLE_USER_HOME
2. distributionPath=wrapper/dists
3. distributionUrl=https\://services.gradle.org/distributions/gradle-
8.5-bin.zip
4. zipStoreBase=GRADLE_USER_HOME
5. zipStorePath=wrapper/dists
Terdapat juga berkas gradlew dan gradlew.bat pada folder root, yaitu
sebuah shell script dan Windows batch script yang digunakan untuk
menjalankan build dengan Wrapper.
Build Scripts
1. /*
3. *
your build.
refer to
https://docs.gradle.org/8.5/userguide/building_swift_projects.html
6. */
7.
8. plugins {
of JDKs
"0.7.0"
11. }
12.
1. /*
3. *
5. * For more details on building Java & JVM projects, please refer to
https://docs.gradle.org/8.5/userguide/building_java_projects.html in
6. */
7.
8. plugins {
Kotlin.
10. alias(libs.plugins.jvm)
11.
12. // Apply the application plugin to add support for building a
13. application
14. }
15.
16. repositories {
18. mavenCentral()
19. }
20.
21. dependencies {
23. testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
24.
26. testImplementation(libs.junit.jupiter.engine)
27.
28. testRuntimeOnly("org.junit.platform:junit-platform-launcher")
29.
31. implementation(libs.guava)
32. }
33.
environments.
35. java {
36. toolchain {
37. languageVersion.set(JavaLanguageVersion.of(21))
38. }
39. }
40.
41. application {
43. mainClass.set("com.dicoding.kotlin.AppKt")
44. }
45.
46. tasks.named<Test>("test") {
48. useJUnitPlatform()
49. }
Source (src)
Mari kita mulai dari folder main terlebih dahulu. Folder ini merupakan
folder utama tempat kita meletakkan berkas kode
dan resources lainnya. Di dalam folder main terdapat folder Kotlin
yang di dalamnya juga terdapat package name dari proyek kita
yaitu com.dicoding.kotlin. Pada package name inilah kita bisa
menambahkan berkas kode nantinya. Saat ini, kita sudah memiliki 1
berkas bernama App.kt:
Semua kode di atas dibuat secara otomatis saat kita membuat proyek
dengan Gradle.
Menjalankan Program Gradle
1. gradle run
Jika proses build berlangsung lama, itu adalah hal normal karena baru
pertama kali dijalankan pada suatu proyek di mana compiler akan
mengunduh beberapa library pendukung agar program dapat
dijalankan dengan baik.
Language Kotlin
GroupId com.dicoding.kotlin
Jika sudah sesuai, klik tombol Create dan Intellij IDEA akan
membuatkan Anda sebuah proyek baru. Berikut adalah tampilan dari
proyek tersebut.
Kotlin Fundamental
Kita sudah tahu cara membangun dan menjalankan program Kotlin.
Kini di sub-modul ini kita akan mempelajari konsep-konsep dasar
(fundamental) pada Kotlin. Kita akan belajar bersama mengenai data
types, function, expression dan juga nullability pada Kotlin.
Hello Kotlin!
// main function
fun main() {
println("Hello Kotlin!")
}
Baris pertama dari kode di atas adalah komentar yang ditandai dengan
tanda //.
// main function
/*
Hello Kotlin
*/
Selanjutnya adalah fungsi yang bernama main(), fungsi yang wajib kita
definisikan ketika membuat sebuah program.
Fungsi main() merupakan sebuah entry point yang otomatis akan
dipanggil ketika program dijalankan. Pada sub-modul berikutnya kita
akan belajar lebih dalam tentang bagaimana mendefinisikan sebuah
fungsi.
Kemudian fungsi println(), fungsi yang akan kita gunakan untuk
mencetak teks ke dalam layar atau konsol.
Fungsi println() membutuhkan satu argumen berupa message dengan
tipe data yang dikehendaki. Tipe data yang didukung untuk kita
masukkan ke dalam fungsi println() ada di tautan ini.
Selain fungsi println(), terdapat juga fungsi print() yang berfungsi sama
seperti fungsi println(). Bedanya, println() akan menambahkan baris
baru setelah selesai mencetak argumen yang diberikan, sementara
fungsi print() tidak melakukan apapun ketika argumen yang diberikan,
selesai dicetak. Untuk memahaminya lebih dalam, coba jalankan kode
berikut:
fun main() {
println(name)
/*
output:
Always true
*/
System.out.print(message)
Namun, ada satu hal yang kita perlu tahu terlebih dahulu,
yaitu Variabel. Umumnya variabel digunakan untuk menyimpan
informasi atau nilai yang akan dikelola di dalam sebuah program.
Sebuah variabel akan membutuhkan kata
kunci var atau val, identifier, type, serta initialization. Kira-kira
strukturnya seperti berikut.
Identifier
Identifier merupakan nama dari sebuah variabel. Pada contoh
kode di atas yang merupakan identifier adalah company. Perlu
diketahui bahwa di dalam sebuah program, kita tidak bisa
membuat lebih dari 1 (satu) variabel dengan nama sama.
Type
Pada bagian inilah kita menentukan tipe data dari variabel
tersebut. Tipe data dibutuhkan agar kompiler dapat mengetahui
bagaimana sebuah data akan digunakan. Tipe data dari contoh
variabel di atas adalah String. Karena Kotlin mendukung type
inference, kita diperbolehkan untuk tidak menuliskan tipe data
secara eksplisit.
Initialization
Dan yang terakhir adalah initialization atau nilai awal dari sebuah
variabel. Pada contoh di atas, yang berperan
sebagai initialization adalah “Dicoding” dan “Dicoding
Academy”.
Tipe data juga menentukan operasi apa saja yang dapat dilakukan
pada sebuah variabel dan bagaimana nilai dari sebuah variabel
disimpan. Contoh, ketika kita menggunakan operator + terhadap dua
variabel yang bertipe String seperti berikut.
fun main() {
print(firstWord + lastWord)
/*
*/
fun main() {
val valueB = 20
print(valueA + valueB)
/*
output: 30
*/
Selain operator tambah (+), ada juga operator lain yang perlu Anda
ketahui untuk memudahkan dalam menuliskan kode Kotlin. Berikut
beberapa di antaranya.
var value = 1
value = value + 2
var anotherValue = 1
anotherValue += 2
4. &&, ||, dan ! adalah operator logika. Operator AND (&&) dan OR
(||) digunakan untuk membandingkan dua nilai sesuai dengan
kondisi yang Anda inginkan. Berbeda dengan operator NOT (!),
biasanya ia digunakan untuk melakukan negasi pada value yang
ada.
5. ++ dan -- adalah operator increment dan decrement yang untuk
menambah atau mengurangi satu nilai.
Tentunya masih banyak simbol spesial dan operator yang bisa Anda
gunakan dalam membangun kode dengan Kotlin. Anda bisa melihat
selengkapnya di Keyword di Kotlin.
Char
Ketika kita mengembangkan sebuah program kita pasti membutuhkan
variabel dengan tipe data yang mampu menyimpan nilai berbentuk
teks. Terdapat dua (2) tipe data yang bisa kita gunakan,
yaitu Char dan String.
Char
Characters direpresentasikan menggunakan tipe Char. Untuk
mendefinisikan sebuah variabel dengan tipe data Char kita bisa
menggunakan tanda kutip tunggal (' ') seperti berikut:
Tipe data Char hanya dapat kita gunakan untuk menyimpan karakter
tunggal. Sebaliknya jika kita memasukkan lebih dari 1 (satu) karakter,
akan terjadi eror:
fun main() {
/*
output:
Vocal A
Vocal B
Vocal C
Vocal D
Vocal C
Vocal B
Vocal A
*/
String
String merupakan tipe data yang mirip dengan Char. Ia dapat
digunakan untuk menyimpan nilai berupa teks. Perbedaannya, String
bisa menampung beberapa karakter di dalamnya.
fun main() {
/*
*/
print("$char ")
/*
output : K o t l i n
*/
Escaped String
fun main() {
print(name)
/*
*/
Raw String
"Line 2\n" +
"Line 3\n" +
"Line 4\n"
Dengan Raw String, kita dapat membuatnya dengan cara yang lebih
mudah yaitu seperti berikut.
fun main() {
Line 2
Line 3
Line 4
""".trimIndent()
print(line)
/*
output:
Line 1
Line 2
Line 3
Line 4
*/
String Template
Di beberapa sub-modul sebelumnya Anda sudah melihat bagaimana
sebuah String ditulis seperti berikut:
"First character of $text is $firstChar"
/*
*/
/*
*/
Variabel yang dapat disisipkan tidak sebatas String. Kita juga bisa
menyisipkan objek lain misal Int atau Double seperti berikut:
val name = "Kotlin"
val old = 3
/*
*/
/*
Dengan string template, kita lebih mudah membuat objek String yang
dinamis.
If Expressions
Saat mengembangkan sebuah program, kita pasti bertemu dengan
alur program yang perlu sebuah kondisi untuk menjalankan
sebuah statement atau expression. Contoh ketika kita ingin
menginisialisasi nilai dari sebuah variabel berdasarkan suatu kondisi.
Untuk menyelesaikannya, gunakan If Expression.
val openHours = 7
val now = 20
val now = 20
} else {
print(office)
Else akan dijalankan jika hasil evaluasi pada expression yang diberikan
menghasilkan nilai false. If merupakan sebuah expressions yang dapat
mengembalikan nilai, sehingga kita dapat menyimpan hasilnya ke
dalam sebuah variabel.
val openHours = 7
val now = 20
} else {
"Office is closed"
print(office)
val now = 7
} else {
"Office is closed"
}
print(office)
Blok else if akan dijalankan jika hasil evaluasi pada branch sebelumnya
bernilai false. Jika hasil evaluasi pada branch else if juga bernilai
nilai false, maka lanjut ke evaluasi branch selanjutnya.
Boolean
Pada submodul sebelumnya, kita telah belajar tentang If
expressions yang menggunakan Boolean expressions. Lalu, apa
itu Boolean? Boolean adalah sebuah tipe data yang hanya memiliki
dua nilai, yaitu true dan false. Terdapat 3 (tiga) operator yang dapat
digunakan pada Boolean.
Conjunction atau AND (&&)
Operator AND (&&) akan mengembalikan nilai true jika semua hasil
evaluasi expression yang diberikan bernilai true.
val officeOpen = 7
val officeClosed = 16
val now = 20
val isOpen = if (now >= officeOpen && now <= officeClosed){
true
} else {
false
/*
*/
/*
*/
/*
*/
if (!isOpen) {
print("Office is closed")
} else {
print("Office is open")
/*
*/
Numbers
Pada sub-modul tipe data kita sudah mempelajari tentang beberapa
tipe seperti Character dan String . Sekarang kita akan mempelajari
beberapa tipe data yang termasuk ke dalam tipe Number. Number
adalah sebuah tipe data yang khusus digunakan untuk menyimpan
nilai dalam bentuk numerik.
Dengan ukuran yang kecil, Byte hanya mampu menyimpan nilai yang
kecil sama halnya seperti Short. Byte biasa digunakan untuk keperluan
proses membaca dan menulis data dari sebuah stream file atau
jaringan.
val byteNumber = 0b11010010
Double (64 Bit)
Sama halnya dengan Long yang memiliki ukuran yang besar, Double
mampu menyimpan nilai numerik yang besar pula. Pada umumnya
Double digunakan untuk menyimpan nilai numerik pecahan sampai
dengan maksimal 15-16 angka di belakang koma.
val doubleNumber: Double = 1.3
Float (32 Bit)
Sama seperti Double, namun memiliki ukuran yang lebih kecil, yakni
hanya sampai 6-7 angka di belakang koma.
val floatNumber: Float = 0.123456789f // yang terbaca hanya
0.1234567
Untuk mengetahui nilai maksimal yang dapat disimpan oleh
suatu tipe Number, kita bisa menggunakan
properti MAX_VALUE. Sementara untuk mengetahui nilai minimal
yang dapat disimpan, gunakan properti MIN_VALUE.
val maxInt = Int.MAX_VALUE
val minInt = Int.MIN_VALUE
println(maxInt)
println(minInt)
/*
output :
2147483647
-2147483648
*/
Jika kita memasukan nilai melebihi nilai maksimal yang dapat
disimpan, maka akan terjadi overflow. Nilai yang akan
dikembalikan adalah nilai minimal yang dapat disimpan.
val maxInt = Int.MAX_VALUE
val overRangeInt = Int.MAX_VALUE + 1 // This operation has led to
an overflow
/*
Output :
print(numberOne + numberTwo)
/*
output : 3
*/
Perlu diketahui, hasil operasi pembagian pada tipe data Int akan
dibulatkan kebawah. Contohnya seperti berikut:
val numberOne: Int = 27
val numberTwo: Int = 10
print(numberOne / numberTwo)
/*
output : 2
*/
Sama seperti perhitungan matematika di mana operasi perkalian
dan pembagian didahulukan, demikian halnya perhitungan pada
Kotlin.
print(5 + 4 * 4)
/*
output: 21
*/
Operasi 4 * 4 akan dilakukan terlebih dahulu, kemudian diikuti 5
+ 16. Jika ingin operasi 5 + 4 dilakukan terlebih dahulu, gunakan
tanda kurung:
print((5 + 4) * 4)
/*
output: 36
*/
Di Kotlin kita tidak bisa melakukan konversi secara langsung.
Contoh, ketika ingin melakukan konversi dari tipe data Byte ke
tipe data Int.
Untuk mengatasinya, lakukan konversi dengan bantuan
beberapa fungsi seperti toInt() berikut:
val byteNumber: Byte = 10
val intNumber: Int = byteNumber.toInt() // ready to go
Kode di atas menggunakan fungsi toInt() untuk melakukan konversi
secara eksplisit dari tipe data Byte ke tipe data Int. Adapun beberapa
fungsi konversi yang dapat kita gunakan antara lain:
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
Contoh lain penggunaan konversi adalah sebagai berikut:
print(intNumber + stringNumber.toInt())
/*
output: 26
*/
Dengan fungsi konversi di atas, nilai 23 yang semula bertipe String di
konversi ke tipe Int yang kemudian dimasukan ke dalam operasi
matematika.
Dengan Kotlin kita juga bisa menuliskan nilai numerik yang “readable”
dengan menggunakan tanda underscores seperti berikut:
/*
output : 1000000
*/
Arrays
Selanjutnya adalah Array, yakni tipe data yang memungkinkan kita
untuk menyimpan beberapa objek di dalam sebuah variabel. Array di
Kotlin direpresentasikan oleh kelas Array yang memiliki
fungsi get dan set serta properti size. Untuk membuat sebuah Array
kita bisa memanfaatkan sebuah library function arrayOf() seperti
berikut:
val array = arrayOf(1, 3, 5, 7)
Kita juga dapat memasukkan nilai dengan berbagai jenis tipe data ke
dalam arrayOf() misalnya:
val mixArray = arrayOf(1, 3, 5, 7 , "Dicoding" , true)
Kotlin juga memungkinkan kita untuk membuat Array dengan tipe data
primitif dengan memanfaatkan beberapa fungsi spesifik berikut:
intArrayOf() : IntArray
booleanArrayOf() : BooleanArray
charArrayOf() : CharArray
longArrayOf() : LongArray
shortArrayOf() : ShortArray
byteArrayOf() : ByteArray
Jika kita ingin membuat Array yang hanya bisa dimasukkan nilai
dengan tipe data Int, gunakan intArrayOf(), misalnya:
Kita juga bisa mendapatkan nilai tunggal dari sekumpulan nilai yang
berada di dalam sebuah Array dengan memanfaatkan indexing seperti
berikut:
val intArray = intArrayOf(1, 3, 5, 7)
print(intArray[2])
/*
Output: 5
*/
Nilai 2 pada kode di atas merupakan indeks atau posisi dari nilai
tunggal yang ingin kita dapatkan. Perlu diketahui bahwa sebuah indeks
selalu dimulai dari 0. Selain mendapatkan nilai tunggal,
dengan indexing kita juga bisa mengubah nilai tunggal tersebut.
Sebagai contoh:
val intArray = intArrayOf(1, 3, 5, 7) // [1, 3, 5, 7]
print(intArray[2])
/*
Output: 11
*/
Nullable Types
Ketika mengembangkan sebuah program, ada satu hal yang tak boleh
kita abaikan. Ia adalah NullPointerException (NPE), sebuah kesalahan
yang terjadi saat ingin mengakses atau mengelola nilai dari sebuah
variabel yang belum diinisialisasi atau variabel yang bernilai null.
Karena sangat umum terjadi dan bisa berakibat fatal, NPE terkenal
dengan istilah “The Billion Dollar Mistake”.
Kotlin akan memaksa kita untuk menentukan nilai awal dari sebuah
objek ketika dibuat dan tidak boleh bernilai null. Jika ingin sebuah
objek bisa bernilai null, kita bisa menambahkan tanda ? setelah
menentukan tipe dari objek tersebut.
val text: String? = null // ready to go
Namun, kita tidak bisa langsung mengakses atau mengelola nilai dari
objek yang sudah ditandai sebagai nullable. Contohnya sebagai berikut.
val text: String? = null
Error:(4, 26) Kotlin: Only safe (?.) or non-null asserted (!!.) calls are
allowed on a nullable receiver of type String?
Lalu, bagaimana cara kita mengakses atau mengelola nilai dari objek
yang ditandai sebagai nullable? Cara mudahnya, periksa objek tersebut
bernilai null atau tidak menggunakan if.
Selain itu, Anda juga bisa menggunakan is atau !is untuk memastikan
sebuah variabel. Compiler akan memastikan tipe data dari variabel
tersebut. Contohnya sebagai berikut.
Pada contoh kode di atas, Kotlin akan secara otomatis mengubah tipe
data Any menjadi String tanpa perlu dikonversi secara manual. Namun,
perlu diperhatikan bahwa bahwa Smart Cast hanya berfungsi jika
kompiler dapat menjamin bahwa variabel tidak akan berubah ketika
setelah diperiksa dan sebelum digunakan.
Oke, sebenarnya ada cara yang lebih elegan untuk penanganan objek
yang ditandai sebagai nullable, yaitu dengan menggunakan Safe
Calls dan Elvis Operator di Kotlin. Seperti apa itu? Mari kita simak di
submodul selanjutnya!
text?.length
Dengan safe call, kompiler akan melewatkan proses jika objek tersebut
bernilai null.
Functions
Function atau fungsi merupakan sebuah prosedur yang memiliki
keterkaitan dengan pesan dan objek. Ketika kita memanggil sebuah
fungsi maka sebuah mini-program akan dijalankan. Fungsi sendiri bisa
diartikan sebagai cara sederhana untuk mengatur program buatan
kita.
return result
}
Pendeklarasian fungsi pada Kotlin diawali dengan kata
kunci fun kemudian dilanjutkan dengan nama fungsi yang dikehendaki.
Selanjutnya adalah parameter yang berada pada fungsi yang
dideklarasikan. Awali dengan nama parameter dan ikuti dengan tipe
parameter itu sendiri yang dipisahkan oleh karakter colon (:). Setiap
parameter yang berada pada sebuah fungsi dipisahkan oleh karakter
koma dan berada di dalam tanda kurung.
Nilai yang akan dikembalikan diikuti oleh kata kunci return. Jika di
dalam suatu fungsi hanya memiliki satu expression untuk menentukan
nilai kembalian, maka fungsi tersebut bisa diubah menjadi expression
body. Kita hanya perlu menambahkan tanda = dan menuliskannya
seperti berikut:
fun setUser(name: String, age: Int): String = "Your name is $name, and you $age years old"
println(user)
printUser("Alfian")
/*
output :
*/
Anatomi Function
Pada materi sebelumnya, kita sudah belajar tentang function (fungsi).
Mulai dari bagaimana cara kita mendeklarasinya, menentukan apakah
fungsi tersebut dapat mengembalikan nilai, serta melampirkan sebuah
argumen ketika fungsi tersebut digunakan.
Pada sub-modul ini kita akan membahas lebih dalam tentang bagian
apa saja yang terdapat dalam sebuah fungsi. Pada dasarnya sebuah
fungsi memiliki 2 (dua) bagian utama yaitu function
header dan function body.
Function Header
Function Name
Function Parameter
Ketika kita mendeklarasikan sebuah fungsi baru, kita bisa atau tanpa
menetapkan parameter tersebut. Parameter adalah data atau nilai
yang disematkan ketika fungsi tersebut dipanggil. Nantinya parameter
akan diproses di dalam fungsi tersebut. Kita bisa melampirkan nilai
konstan atau variabel untuk sebuah fungsi ketika ia dipanggil.
Parameter dari sebuah fungsi terdiri dari nama dan tipe dari
parameter itu sendiri. Ia digunakan untuk menentukan nilai atau
variabel apa yang dapat dilampirkan. Setiap parameter dipisahkan
oleh tanda (,). Catatan: setiap parameter bersifat read-only, sehingga
kita hanya diijinkan untuk menggunakan nilainya untuk diproduksi.
Terakhir adalah return type. Setiap fungsi yang kita deklarasi sejatinya
akan selalu mengembalikan dan nilai yang akan dikembalikan bisa kita
gunakan untuk keperluan lain. Misalnya untuk dijadikan sebagai
argumen untuk fungsi lainnya.
Lalu apakah tipe ini harus ditentukan setiap deklarasi sebuah fungsi?
Tentu tidak. Jika kita tidak menentukan return type, secara implisit
fungsi tersebut akan mengembalikan nilai dengan tipe Unit, yaitu
return type yang tidak mengembalikan nilai signifikan.
Function Body
Sebaliknya, jika kita tidak ingin mengembalikan nilai, kita tidak perlu
menambahkannya seperti yang disebutkan di atas.
Setiap fungsi yang kita deklarasikan, memiliki ruang lingkup tersendiri.
Contohnya saat kita mendeklarasi sebuah variabel di dalamnya,
variabel tersebut akan menjadi variabel lokal untuk fungsi itu sendiri.
Dengan demikian, variabel tersebut tidak dapat diakses dari fungsi
lainnya meskipun berada di dalam satu kelas yang sama.
Named Argument
Untuk mengatasi hal ini Kotlin menawarkan sebuah cara. Dengan ini,
kita tak perlu lagi menghafal posisi dari sebuah parameter. Karena
ketika sebuah fungsi dipanggil, kita bisa menentukan argumen dari
parameter mana yang ingin dilampirkan dengan memanggil nama dari
parameter tersebut. Misalnya kita mempunyai sebuah fungsi seperti
berikut:
fun main() {
print(fullName)
}
fun getFullName(first: String, middle: String, last: String): String {
fun main() {
print(fullName)
Dengan cara seperti di atas, kita tidak perlu lagi menghafal posisi dari
parameter jika ingin melampirkan sebuah argumen. Cukup hafalkan
nama dari parameter tersebut.
Default Argument
Untuk menambahkan nilai default itu sendiri pun cukup mudah, yaitu
dengan cara menempatkannya langsung tepat di samping dari
parameter seperti halnya ketika ingin menginisialisasikan sebuah nilai
untuk variabel. Contohnya seperti berikut:
fun getFullName(
fun main() {
print(fullName)
/*
*/
Menarik bukan? Ketika kita telah menetapkan nilai default, kita tak
perlu khawatir saat lupa melampirkan sebuah argumen. Tentunya ini
menghindari kita dari eror. Meskipun begitu, kita tetap bisa
melampirkan sebuah argumen. Contohnya seperti berikut:
fun main() {
val fullName = getFullName(first = "Dicoding")
print(fullName)
/*
*/
return number.sum()
fun main() {
val number = sumNumbers(10, 20, 30, 40)
print(number)
/*
output : 100
*/
fun main() {
print(number)
return number.size
/*
output : 5
*/
Lalu, kapan kita membutuhkan vararg? Ketika sebuah fungsi yang
menggunakannya tidak mengetahui jumlah argumen yang akan
disematkan ketika fungsi tersebut dipanggil. Contoh penerapan bisa
kita liat pada fungsi String.format(), di mana fungsi tersebut terdapat
parameter yang ditandai dengan vararg dan dapat disematkan
beberapa argumen tanpa harus tahu batasannya.
Ketika kode di atas dijalankan, proses kompilasi akan gagal dengan log
eror sebagai berikut:
Kotlin: Multiple vararg-parameters are prohibited
fun main() {
...
fun main() {
...
Vararg vs Array
...
Dari sini kita bisa lihat langsung letak perbedaannya di mana. Ketika
fungsi di atas dipanggil, fungsi tersebut membutuhkan argumen
berupa nilai yang sudah berbentuk Array seperti berikut:
fun main() {
...
fun main() {
...
fun main() {
val officeOpen = 7
val now = 10
val isOpen = now > officeOpen
if (!isOpen) {
print("Office is closed")
} else {
print("Office is open")
}
}
Outputnya adalah
Fungsi yang digunakan untuk mencetak teks ke dalam layar atau konsol dan
menambahkan baris baru adalah ...
println()
system.out.cetak()
print()
printNewLine()
Manakah cara yang tidak menghasilkan error dalam memanggil fungsi tersebut?
getFullAddress()
getFullAddress(streetName = "Jl. Margonda")
getFullAddress(streetName = "Jl. Margonda" , number = 50)
Terdapat beberapa bagian dari control flow yang akan kita pelajari,
antara lain:
When Expression
Expression & Statement
While and Do While
Range and For Loop
Break and Continue Labels
} else {
print("Office close")
Nah, perlu Anda ketahui bahwa di dalam sebuah expression juga bisa
terdapat sebuah expression lagi. Contohnya seperti berikut.
fun main() {
sum(1 , 1 * 4)
}
fun main() {
val value1 = 10
val value2 = 10
sum(value1, value2)
}
When Expressions
Untuk menentukan statement atau expression kita menggunakan If
Expression. Selain itu kita juga bisa gunakan When Expression,
yakni mekanisme yang memungkinkan nilai dari sebuah
variabel/expression, mampu mengubah alur program.
val value = 7
when(value){
/*
output: value is 7
*/
val value = 20
when(value){
/*
val value = 7
println(stringOfValue)
/*
output : value is 7
*/
else adalah hal wajib jika kita menggunakan when expression untuk
mengembalikan nilai. Bagaimana jika kita melewatkannya? Akan tampil
eror berikut:
'when' expression must be exhaustive, add necessary 'else'
branch
Jika kita memiliki dua atau lebih baris kode yang akan kita jalankan di
setiap branch, kita bisa memindahkannya ke dalam curly braces seperti
berikut:
val value = 7
6 -> {
println("Six")
"value is 6"
7 -> {
println("Seven")
"value is 7"
8 -> {
println("Eight")
"value is 8"
else -> {
println("undefined")
}
println(stringOfValue)
/*
output :
Seven
value is 7
*/
when(anyType){
/*
*/
Selain itu, when expression juga bisa kita gunakan untuk memeriksa
nilai yang terdapat pada sebuah Range atau Collection. Range sendiri
merupakan salah satu tipe data yang unik di mana kita dapat
menentukan nilai awal dan nilai akhir. Range dan Collection akan
dibahas terpisah pada sub-modul berikutnya.
Berikut adalah contoh saat kita hendak mengecek apakah sebuah nilai
ada di dalam sebuah Range atau tidak.
val value = 27
when(value){
/*
*/
Sejak Kotlin 1.3, kita dapat menangkap subjek dari when expression di
dalam sebuah variabel. Contohnya seperti berikut:
fun main() {
if (anyType is Long){
} else {
when (anyType) {
is Long -> println("the value has a Long type")
Hello World
Hello World
Hello World
Hello World
Hello World
fun main() {
println("Hello World")
println("Hello World")
println("Hello World")
println("Hello World")
println("Hello World")
}
Think! Bagaimana jika teks yang harus ditampilkan berjumlah banyak?
Tentu kita tidak mungkin menuliskan fungsi println() sesuai dengan
jumlah yang kita ingin tampilkan.
Perulangan terdiri dari While, Do While dan For Loop. Sub-modul ini
akan membahas While dan Do While. Sementara For Loop akan
dibahas terpisah pada sub-modul berikutnya.
While
fun main() {
var counter = 1
println("Hello, World!")
counter++
/*
output :
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
*/
Perhatikan kondisi dari While di atas, selama nilai dari variabel counter
kurang dari sama dengan 7 maka kode yang di dalamnya akan terus
dilakukan. Lalu ketika kondisi tersebut sudah tak terpenuhi maka
proses perulangan akan dihentikan.
Jika kondisi yang diberikan tidak terpenuhi sejak awal maka proses
perulangan tidak akan dijalankan. Untuk mengujinya Anda bisa
menulis dan menjalankan kode berikut:
fun main() {
var counter = 8
println("Hello, World!")
counter++
}
Dengan While kita tidak perlu menuliskan fungsi println() secara
berulang untuk mencetak teks ke dalam konsol seperti contoh kasus di
awal.
Do While
fun main() {
var counter = 1
do {
println("Hello, World!")
counter++
/*
output:
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
*/
fun main() {
do {
print(value)
Range
Seperti yang disampaikan sebelumnya, Range merupakan salah satu
tipe yang unik pada kotlin. Kita dapat menentukan nilai awal dan nilai
akhir pada Range. Range direpresentasikan dengan operator .. atau
dengan fungsi rangeTo() dan downTo().
fun main() {
print(rangeInt.step)
/*
output: 1
*/
Dan untuk mengubah nilai dari step bisa dilakukan ketika kita
menginisialisasi nilai yang dicakup Range itu sendiri:
fun main() {
rangeInt.forEach {
print("$it ")
println(rangeInt.step)
}
/*
output: 1 3 5 7 9 2
*/
Pada kode di atas kita menentukan nilai step adalah 2, maka nilai yang
dicakup variabel rangeInt adalah 1, 3, 5, 7, 9.
Kita juga bisa menentukan nilai yang dicakup pada Range dengan
urutan terbalik seperti berikut:
Kita juga bisa memeriksa apakah suatu nilai ada pada cakupan nilai
Range.
fun main() {
if (7 in tenToOne) {
println("Value 7 available")
}
/*
*/
fun main() {
println("Value 7 available")
/*
*/
Nah, di atas kita telah memeriksa apakah suatu nilai ada pada nilai
cakupan Range. Sebaliknya, kita juga bisa memeriksa apakah suatu
nilai tidak ada pada nilai cakupan Range tersebut. Kita bisa
menggunakan kata kunci !in seperti ini:
fun main() {
}
}
/*
*/
For Loop
fun main() {
for (i in ranges){
println("value is $i!")
}
}
/*
output :
value is 1!
value is 2!
value is 3!
value is 4!
value is 5!
*/
fun main() {
for (i in ranges){
println("value is $i!")
/*
output :
value is 1!
value is 2!
value is 3!
value is 4!
value is 5!
*/
Selain itu, kita juga dapat menuliskan For loop menggunakan range
expression seperti berikut.
fun main() {
for (i in ranges ){
println("value is $i!")
/*
output :
value is 1!
value is 4!
value is 7!
value is 10!
*/
Pada kode di atas, kita menambahkan ekstensi step yang akan
mengembalikan nilai baru dengan tipe IntProgression dengan jarak
nilai sebelumnya adalah 3.
Kita juga dapat mengakses indeks untuk setiap elemen yang ada
pada ranges dengan memanfaatkan fungsi withIndex() seperti berikut.
fun main() {
/*
output :
*/
fun main() {
/*
output :
value is 1!
value is 4!
value is 7!
value is 10!
*/
Catatan:
Kode ini merupakan contoh dari penerapan Lambda Expression. Jika
Anda merasa asing dengan penulisan kode tersebut, tenang saja, kita
akan mempelajarinya pada modul-modul selanjutnya. Untuk sekarang,
cukup gunakan saja terlebih dahulu.
fun main() {
print(i)
/*
output: 123null5null7
*/
Proses perulangan pada kode di atas akan menghasilkan nilai null. Jika
kita mengelola nilai tersebut, ada potensi NullPointerException di
sana. Lalu bagaimana kita melewatkan atau menghentikan proses
perulangan jika nilai yang dihasilkan bernilai null? Nah, di sini kita bisa
menggunakan Break dan Continue.
Berikut adalah contoh proses iterasi pada kode di atas. Kita akan coba
melewatkannya jika nilai yang dihasilkan adalah null.
fun main() {
for (i in listOfInt) {
if (i == null) continue
print(i)
}
/*
output: 12357
*/
Pada kode di atas kita menggunakan kata kunci continue. Jika hasil
evaluasi expression yang diberikan bernilai true, maka proses iterasi
akan dilewatkan dan lanjut ke proses iterasi berikutnya.
fun main() {
for (i in listOfInt) {
if (i == null) break
print(i)
Penggunaan break pada kode di atas akan langsung menghentikan proses iterasi jika
variabel i bernilai null.
fun main() {
loop@ for (i in 1..10) {
println("Outside Loop")
for (j in 1..10) {
println("Inside Loop")
if ( j > 5) break@loop
/*
output :
Outside Loop
Inside Loop
Inside Loop
Inside Loop
Inside Loop
Inside Loop
Inside Loop
*/
Pada kode diatas, break yang sudah ditandai dengan label akan
dilompati ke titik awal proses perulangan yang sudah ditandai dengan
label. break akan menghentikan proses perulangan terluar dari dalam
proses perulangan, di mana break tersebut dipanggil.
o While
While bersifat Entry Controlled Loop. Artinya, kondisi yang
diberikan akan dievaluasi terlebih dahulu. Jika kondisi
tersebut terpenuhi maka proses perulangan akan
dijalankan.
o Do While
Do While bersifat Exit Controlled Loop di mana proses
perulangan akan langsung dijalankan di awal. Jika telah
selesai, barulah kondisi yang diberikan akan dievaluasi.
o For Loop
For merupakan konsep perulangan pada blok yang sama
selama hasil evaluasi kondisi yang diberikan terpenuhi atau
bernilai true. For memanfaatkan tipe data Range untuk
menentukan kondisi yang akan dievaluasi.
Saat menggunakan While dan Do While perhatikan infinite loop,
yaitu kondisi di mana proses perulangan berlangsung terus
menerus sampai aplikasi menjadi crash.
Saat menerapkan perulangan, kita bisa memanfaatkan kata
kunci break dan continue. Kedua kata kunci tersebut digunakan
untuk menentukan proses perulangan akan seperti apa di mana
break digunakan untuk menghentikan proses perulangan
walaupun hasil evaluasi masih menghasil true dan continue
digunakan untuk melanjutkan proses perulangan selanjutnya.
112123
123
123123123
jjjjjj
when (a) {
// ...
}
fun main() {
var counter = 3
do {
print("Hi Kotlin! ")
counter++
} while (counter < 3)
}
Sebelum mempelajari OOP lebih jauh, ada hal penting yang perlu Anda
perhatikan, yakni 4 pilar dalam OOP. Mengapa itu menjadi penting?
Coba bayangkan sebuah perusahaan besar seperti Google yang
menangani ratusan bahkan ribuan karyawannya. Dalam hal ini
tentunya Google memiliki serangkaian aturan dan kebijakan yang tepat
agar mencapai tujuan. Selaras dengan hal tersebut, ketika
mengembangkan sebuah perangkat lunak, pastinya kita akan memiliki
jumlah sistem yang banyak. Oleh karena itu, kita wajib menerapkan
sebuah aturan dan kebijakan dalam pengembangan tersebut guna
menghindari kompleksitas.
Dari completion suggestion yang tersedia pada IntelliJ Idea, kita bisa
melihat beberapa fungsi yang dapat digunakan oleh objek someString.
Kita bisa menggunakan fungsi reverse() untuk membuat urutan huruf
disusun secara terbalik, fungsi toUpperCase() yang dapat membuat
huruf menjadi kapital atau fungsi toLowerCase() yang dapat membuat
menjadi huruf kecil.
fun main() {
println(someString.reversed())
println(someString.uppercase())
println(someString.lowercase())
/*
Output:
gnidociD
DICODING
dicoding
*/
Kita juga dapat mengubah tipe data dengan mengakses fungsi yang
tersedia dari sebuah objek String.
fun main() {
println(someInt is Int)
println(someDouble is Double)
/*
Output:
true
true
*/
Hasil dari output kode menunjukan nilai true pada kedua variabel
tersebut, yang artinya kita telah berhasil mengubah suatu tipe data
String ke tipe data lainnya dengan menggunakan fungsi yang terdapat
pada objek String.
Class
Seperti yang telah dijelaskan dalam pembahasan
objek, Class merupakan sebuah blueprint. Di dalam kelas ini kita
mendefinisikan sesuatu yang
merupakan attribute ataupun behaviour. Contohnya pada sebuah
kelas Kendaraan, atributnya berupa roda, warna, nomor kendaraan,
merk, dll. Sedangkan untuk behaviour nya yaitu maju, mundur, belok
kanan, belok kiri, berhenti. Contoh lainnya pada sebuah
kelas Hewan atributnya berupa nama, berat, umur, termasuk mamalia
atau bukan dll. Sedangkan untuk behaviour-nya bisa makan, tidur,
berjalan, dsb.
Properti dalam sebuah kelas memiliki tipe data. Contoh, untuk properti
berat pada kelas Hewan dapat bertipe Double, nama dapat
bertipe String, umur dapat bertipe Int. dan indikasi mamalia dapat
bertipe Boolean. Selain itu, ia juga bisa memiliki sebuah behavior
seperti makan dan tidur. Jika kelas Hewan kita representasikan dalam
bentuk tabel maka akan terlihat seperti:
Animal
Properti Method
name: String eat()
weight: Double sleep()
age: Int
isMammal: Boolean
Membuat Class
Untuk mendefinisikan kelas dalam Kotlin, Anda cukup gunakan kata
kunci class diikuti dengan nama kelas yang akan dibuat. Mari kita buat
contoh kelas pada Kotlin.
class Animal
fun eat(){
println("$name makan!")
}
fun sleep() {
println("$name tidur!")
Sama seperti variabel, Anda bisa gunakan val atau var diikuti dengan
nama objek yang akan dibuat. Setelah itu, gunakan tanda = untuk
menunjukkan bahwa kita akan menginisialisasi suatu objek dan
panggil nama kelas dengan tanda kurung di akhir. Tanda kurung
tersebut menunjukan bahwa kita membuat sebuah objek baru. Di
dalam tanda kurung, kita dapat menambahkan nilai properti sesuai
yang dibutuhkan pada primary constructor kelasnya.
Jika kita coba membuat objek dari kelas yang sudah kita buat, kodenya
akan terlihat seperti ini.
dicodingCat.eat()
dicodingCat.sleep()
dicodingCat.weight = 6.0
dicodingCat.age = 3
dicodingCat.eat()
dicodingCat.sleep()
Properties
Sebuah kelas dalam Kotlin tentu memiliki properti. Masing - masing
kelas memiliki properti yang berbeda. Contoh sebelumnya pada
kelas Animal, properti yang dimiliki
berupa name, weight, age dan isMammal.
Sama seperti variabel yang sudah kita pelajari pada sub-modul Data
Types, properti dapat dideklarasikan sebagai nilai mutable dengan
menggunakan var atau sebagai nilai read-only dengan
menggunakan val.
Property Accessor
Secara standar ketika properti pada kelas dibuat mutable, maka Kotlin
akan menghasilkan fungsi getter dan setter pada properti tersebut.
Jika properti pada sebuah kelas dibuat read-only, Kotlin hanya akan
menghasilkan fungsi getter pada properti tersebut. Namun sebenarnya
Anda bisa membuat fungsi getter dan setter secara manual jika pada
kasus tertentu Anda perlu untuk override fungsi tersebut.
class Animal{
var name: String = "Dicoding Miaw"
fun main(){
println("Nama: ${dicodingCat.name}" )
dicodingCat.name = "Goose"
println("Nama: ${dicodingCat.name}")
/*
output:
Nama: Goose
*/
Tetapi jika kita melakukan override pada fungsi getter dan juga setter ,
maka kita dapat menambahkan kode lain pada fungsi getter sesuai
dengan kebutuhan. Mari kita coba modifikasi kode sebelumnya
menjadi:
class Animal{
get(){
return field
set(value){
field = value
fun main(){
println("Nama: ${dicodingCat.name}" )
dicodingCat.name = "Goose"
println("Nama: ${dicodingCat.name}")
/*
output:
Nama: Goose
*/
Urutan pendefinisian fungsi get() dan set() tidaklah penting, kita dapat
mendefinisikan fungsi get() tanpa mendefinisikan fungsi set() dan juga
sebaliknya. Yang terpenting pendeklarasiannya dilakukan setelah
mendeklarasikan properti tersebut. Pada fungsi get(), kita perlu
mengembalikan nilai sesuai tipe data dari propertinya atau kita dapat
mengembalikan nilai dari properti itu sendiri dengan
menggunakan keyword field. Sedangkan untuk fungsi set() kita
memerlukan sebuah parameter. Ini merupakan sebuah nilai baru yang
nantinya akan dijadikan nilai properti. Pada kode di atas parameter
tersebut ditetapkan dengan nama value.
Nah, salah satu alternatif solusi yang bisa dipakai adalah mengisinya
dengan nilai null terlebih dahulu seperti berikut.
fun main() {
print(name?.length)
Namun, pendekatan ini memerlukan safe call operator (?.) setiap kali
mengakses property atau fungsi di dalamnya. Tentunya ini menambah
pekerjaan untuk mengecek apakah variabel tersebut null atau tidak,
padahal kita sudah yakin bahwa variabel tersebut sudah pasti ada
nilainya nanti.
Lateinit
fun main() {
Catatan:
Hal yang perlu diperhatikan adalah lateinit harus disandingkan dengan
keyword var (tidak bisa menggunakan val). Hal ini berbeda dengan
Lazy property yang nanti akan dibahas.
Property Delegation
Pengelolaan properti kelas baik itu memberikan atau mengubah
sebuah nilai dapat didelegasikan kepada kelas lain. Dengan ini kita
dapat meminimalisir boilerplate dalam penulisan getter dan setter (jika
properties menggunakan var) pada setiap kelas yang kita buat.
Sebagai contoh, kita memiliki tiga buah kelas yang di dalamnya
memiliki satu properti String. Jika kita ingin
menerapkan getter dan setter pada setiap properti kelasnya, maka kita
perlu menuliskan getter dan setter tersebut pada seluruh kelas. Hal
tersebut dapat mengurangi efisiensi dalam menuliskan kode karena
terlalu banyak kode yang harus kita tulis secara berulang. Solusinya,
kita perlu membuat sebuah kelas yang memang bertugas untuk
mengatur atau mengelola fungsi getter dan setter untuk sebuah
properti kelas. Teknik tersebut pada Kotlin dinamakan Delegate.
import kotlin.reflect.KProperty
class DelegateName {
return value
value = newValue
class Animal {
class Animal {
class Person {
class Hero {
Mari kita membuat sebuah objek, ubah dan akses nilai propertinya
pada setiap kelas, kemudian jalankan. Maka hasilnya akan seperti pada
kode berikut:
fun main() {
person.name = "Dimas"
hero.name = "Gatotkaca"
println("Nama Pahlawan: ${hero.name}")
/*
output:
Fungsi ini sama seperti setter untuk properti name pada class
Animal@17f052a3
Fungsi ini sama seperti getter untuk properti name pada class
Animal@17f052a3
Fungsi ini sama seperti setter untuk properti name pada class
Person@2e0fa5d3
Fungsi ini sama seperti getter untuk properti name pada class
Person@2e0fa5d3
Fungsi ini sama seperti setter untuk properti name pada class
Hero@5010be6
Fungsi ini sama seperti getter untuk properti name pada class
Hero@5010be6
*/
Pada contoh di atas, delegasi hanya dapat digunakan oleh properti
yang memiliki tipe data String. Namun kita juga dapat membuat
sebuah delegasi kelas umum yang dapat digunakan oleh seluruh tipe
data dengan memanfaatkan tipe data Any.
import kotlin.reflect.KProperty
class DelegateGenericClass {
return value
value = newValue
class Animal {
var name: Any by DelegateGenericClass()
Kemudian mari kita membuat sebuah objek dari kelas Animal, ubah
dan akses nilai propertinya kemudian jalankan. Maka hasilnya akan
seperti pada kode berikut:
fun main(){
animal.weight = 6.2
animal.age = 1
println("Nama: ${animal.name}")
println("Berat: ${animal.weight}")
/*
output:
Fungsi ini sama seperti getter untuk properti weight pada class
Animal@17f052a3
Berat: 6.2
Fungsi ini sama seperti getter untuk properti age pada class
Animal@17f052a3
Umur: 1 Tahun
*/
Primary Constructor
Ketika suatu objek dibuat, semua properti pada kelas tersebut harus
memiliki nilai. Kita dapat langsung menginisialisasi pada properti
tertentu atau menginisialisasinya melalui constructor (konstruktor).
Konstruktor merupakan fungsi spesial yang digunakan untuk
menginisialisasi properti yang terdapat pada kelas tersebut.
Terdapat 2 (dua) tipe konstruktor pada Kotlin, yaitu primary
constructor dan secondary constructor. Yuk, kita coba
mempelajarinya bersama.
Primary Constructor
Seperti namanya, jika akan membuat suatu objek dari sebuah kelas
dan kelas tersebut memiliki primary constructor di dalamnya, kita harus
mengirim nilai sesuai properti yang dibutuhkan. Penulisan primary
constructor mirip seperti parameter pada fungsi. Properti cukup
dituliskan pada header class diawali dengan var atau val. Perhatikan
kode berikut.
class Animal(val name: String, val weight: Double, val age: Int, val
isMammal: Boolean)
Pada baris kode tersebut, kita tidak hanya membuat sebuah kelas,
tetapi sekaligus menambahkan sebuah primary constructor pada kelas
tersebut. Sekarang mari kita coba membuat objek dari kelas tersebut.
fun main(){
/*
output:
*/
class Animal(var name: String, var weight: Double, var age: Int = 0, var
isMammal: Boolean = true)
fun main(){
/*
output:
*/
Kita juga dapat secara eksplisit memilih properti yang ingin kita
berikan nilai dengan menambahkan nama properti dan
tanda = sebelum mengisikan nilai properti.
Init block
Kotlin menyediakan blok init yang memungkinkan kita untuk
menuliskan properti di dalam body class ketika kita
menggunakan primary constructor. Memang, memiliki kode banyak di
dalam body class bukanlah hal yang baik. Kotlin bertujuan agar kita
dapat menuliskan kode seminimal mungkin. Tapi blok init di sini
memiliki beberapa fungsi selain menginisialisasi properti kelas. satu
fungsi lainnya adalah untuk membantu dalam memvalidasi sebuah
nilai properti sebelum diinisialisasi. Pada kelas Animal contohnya, kita
dapat melakukan verifikasi bahwa berat dan umur hewan tidak boleh
bernilai kurang dari nol.
init {
name = pName
isMammal = pIsMammal
fun main() {
/*
output:
*/
init {
this.name = name
this.isMammal = isMammal
Secondary Constructor
Secondary constructor digunakan ketika kita ingin menginisialisasi
sebuah kelas dengan cara yang lain. Anda dapat membuat lebih dari
satu secondary constructor. Sebagai contoh, kita bisa menambahkan
secondary constructor pada kelas Animal:
init {
this.name = name
this.isMammal = false
this.isMammal = isMammal
fun main() {
/*
output:
*/
Default Constructor
Kotlin secara otomatis membuat sebuah default constructor pada kelas
jika kita tidak membuat sebuah konstruktor secara manual. Perhatikan
kode berikut:
class Animal{
fun main(){
/*
output:
*/
Visibility Modifiers
Kali ini kita akan mengenal beberapa tentang visibility modifiers atau
hak akses pada Kotlin. Tentunya, tidak semua properti dan method
pada sebuah kelas memiliki hak akses publik. Ada beberapa yang
hanya dapat diakses dari dalam dan ada yang dapat diakses dari luar
kelasnya. Dengan menentukan hak akses tersebut, kita dapat
membatasi akses data pada sebuah kelas, inilah yang disebut
dengan encapsulation pada salah satu pilar OOP.
Public
Berbeda dengan bahasa pemrograman umumnya, default
modifier pada Kotlin adalah public. Ketika sebuah anggota memiliki
hak akses public maka anggota tersebut dapat diakses dari luar
kelasnya melalui sebuah objek kelas tersebut.
Private
Ketika suatu anggota memiliki hak akses private, maka anggota
tersebut tidak dapat diakses dari luar scope-nya. Untuk
menggunakan modifier private kita perlu
menambahkan keyword private seperti contoh berikut:
class Animal(
)
fun main() {
return name
name = newName
return name
name = newName
fun main() {
println(dicodingCat.getName())
dicodingCat.setName("Gooose")
println(dicodingCat.getName())
/*
output:
Dicoding Miaw
Gooose
*/
Protected
Hak akses protected mirip seperti private, namun pembatasannya
lebih luas dalam sebuah hirarki kelas. Hak akses protected digunakan
ketika kita menginginkan sebuah anggota dari induk kelas dapat
diakses hanya oleh kelas yang merupakan turunannya. Perhatikan
kode di bawah ini untuk contoh penggunaan hak akses protected.
Pada kode tersebut, properti weight pada kelas Animal memiliki hak
akses protected. Kita tetap bisa mengaksesnya dari kelas Cat yang
termasuk dalam hirarki kelas Animal. Namun kita tidak dapat
mengakses properti tersebut secara langsung dari luar hirarki
kelasnya. Eror akan terjadi jika kita melakukan hal tersebut.
fun main() {
val cat = Cat("Dicoding Miaw", 2.0)
Internal
Internal merupakan hak akses baru yang diperkenalkan pada Kotlin.
Hak akses ini membatasi suatu anggota untuk dapat diakses hanya
pada satu modul. Berikut ini contoh penggunaan hak akses internal:
Overloading
Di awal, kita sudah mengenal salah satu pilar dari OOP, yakni
Polymorphism. Polymorphism merupakan kemampuan objek, variabel,
atau fungsi yang dapat memiliki berbagai bentuk. Alhasil, kita dapat
mengembangkan sebuah program secara umum, bukan spesifik.
fun eat() {
println("$name makan!")
fun sleep() {
println("$name tidur!")
fun main() {
dicodingCat.eat()
dicodingCat.eat("Ikan Tuna")
/*
Output:
*/
class Calculator {
fun min(value1: Int, value2: Int) = if (value1 < value2) value1 else
value2
fun main() {
println(calc.add(2, 4))
println(calc.add(2.5, 2.2))
println(calc.add(6f, 7f))
println(calc.add(1, 2, 3))
println(calc.min(9, 2))
println(calc.min(17.2, 18.3))
/*
output
4.7
13.0
17.2
*/
Inheritances
Dalam gambaran dunia nyata, banyak objek yang berbeda tetapi
punya kesamaan atau kemiripan tertentu. Contohnya Kucing dan
Kambing memiliki banyak kesamaan karena objek tersebut merupakan
hewan. Kucing merupakan hewan mamalia, begitu juga dengan
kambing. Mungkin yang membedakan objek tersebut adalah cara
mereka mencari makanan dan jenis makanan yang dimakan. Sama
halnya pada OOP, beberapa objek yang berbeda bisa saja memiliki
kesamaan dalam hal tertentu. Di situlah
konsep inheritance atau pewarisan yang merupakan salah satu pilar
dari OOP harus diterapkan. Pewarisan dapat mencegah kita
melakukan perulangan kode. Untuk lebih memahaminya lihatlah
contoh bagan pada sebuah kelas berikut:
class Cat(val name: String, val furColor: String, val weight: Double, val
age: Integer, val numberOfFeet: Integer, val isCarnivore: Boolean) {
fun eat(){
fun sleep() {
fun playWithHuman() {
Tidak ada masalah dengan kode tersebut, tetapi ketika kita akan
membuat kelas dari diagram lainnya contohnya Fish maka kita harus
menuliskan ulang properti seperti name, weight, age dan properti atau
fungsi yang sama lainnya. Hal ini dapat mengurangi efisiensi dalam
menuliskan kode.
Animal
+ name: String
+ weight: Double
+ age: Integer
+ isCarnivore: Boolean
- eat()
- sleep()
Cat Fish Snake
+ furColor: String + scaleColor: String + skinColor: String
Mari kita buat kelas Animal yang akan berperan sebagai parent
class seperti berikut:
open class Animal(val name: String, val weight: Double, val age: Int, val
isCarnivore: Boolean){
fun playWithHuman() {
fun main(){
dicodingCat.playWithHuman()
dicodingCat.eat()
dicodingCat.sleep()
/*
output:
*/
Lalu, bagaimana jika Anda tidak ingin mengambil alih penuh, tetapi
hanya ingin menambahkan implementasi dari yang sudah di parent
class? Jawabannya adalah dengan menggunakan keyword super.
super.eat()
fun main(){
dicodingCat.eat()
/*
output:
Abstract Class
Kita lanjut ke salah satu pilar lain pada OOP, yakni Abstraction.
Abstraction adalah konsep di mana Anda menyembunyikan detail
tertentu dari implementasi suatu objek dan hanya menunjukkan
fungsionalitas yang relevan atau penting bagi pengguna objek
tersebut. Jadi, pada kelas induknya kita hanya mendefinisikan nama
method dan property-nya saja, untuk implementasinya nanti
diserahkan ke kelas turunannya. Hal ini berbeda dengan konsep
inheritance sebelumnya yang seluruh method dan property sudah
memiliki implementasi pada kelas induk.
Abstract Class
Seperti namanya, abstract merupakan gambaran umum dari sebuah
kelas. Ia tidak dapat direalisasikan dalam sebuah objek. Pada sub-
modul sebelumnya kita sudah mempunyai kelas Animal. Secara
harfiah hewan merupakan sebuah sifat. Kita tidak tahu bagaimana
objek hewan tersebut. Kita tahu bentuk kucing, ikan dan ular seperti
apa tetapi tidak untuk hewan. Maka dari itu konsep abstract class perlu
diterapkan agar kelas Animal tidak dapat direalisasikan dalam bentuk
objek namun tetap dapat menurunkan sifatnya kepada child class-nya.
abstract class Animal(var name: String, var weight: Double, var age: Int,
var isCarnivore: Boolean){
fun eat(){
fun sleep(){
fun main(){
Ketika kita mencoba membuat objek dari kelas Animal, akan terdapat
eror berikut:
Interfaces
Interfaces merupakan suatu konsep sifat umum yang nantinya
digunakan oleh suatu kelas agar dapat memiliki sifat tersebut.
Interface sangat mirip dengan abstract class, namun tanpa sebuah
properti deklarasi dan fungsi yang dideklarasikan tanpa isi. Tujuan dari
interface ini hanya untuk diimplementasikan oleh sebuah kelas. Kelas
yang mengimplementasikan sebuah interface diharuskan melakukan
override seluruh properti dan fungsi sekaligus mendefinisikan isi
fungsi yang terdapat pada interfaces-nya.
interface IFly {
fun fly()
interface IFly {
fun fly()
interface IWalk {
interface IDrink {
override val age: Int = 7 // this property must exist, try to remove it
override val isEating = true // this property optional, try to remove it
fun main(){
camel.walk()
Extensions
Kotlin memungkinkan kita untuk menambahkan sebuah fungsi baru
pada sebuah kelas tanpa harus mewarisi kelas tersebut. Misalnya, jika
ingin menambahkan fungsi baru untuk kelas Int, kita akan
menuliskannya seperti berikut.
fun printInt(){
println("value $this")
fun Int.printInt() {
print("value $this")
fun main() {
10.printInt()
/*
output : value 10
*/
fun main() {
println(10.plusThree())
}
return this + 3
/*
output : 13
*/
Extension Properties
Seperti yang disebutkan di awal, Kotlin juga
mendukung extension untuk menambah sebuah properti baru pada
sebuah kelas tanpa harus menyentuh kode di dalam kelas tersebut.
get() = this / 2
fun main() {
println(10.slice)
/*
output : 5
*/
Infix Function
Anda sudah mempelajari cara membuat sebuah function, mengelola,
hingga menggunakannya. Untuk memanggil sebuah function, Anda
melakukannya dengan memanggil nama function tersebut dan diakhiri
dengan kurung buka tutup. Namun, ternyata ada cara lain dalam
pemanggilan sebuah function. Anda bisa menggunakan infix function
untuk memanggil suatu fungsi dengan cara yang lebih ringkas dan
mirip dengan pemakaian operator matematika.
fun build() {
addHero("Spidermen") // Correct
}
Nullable Receiver
Menariknya, kita bisa juga mendeklarasikan sebuah extension
dengan nullable receiver type. Alhasil, extension tersebut bisa dipanggil
pada objek yang bahkan nilainya null.
get() = this?.div(2) ?: 0
fun main() {
println(value.slice)
/*
output : 0
*/
Lalu kapan kita membutuhkannya? Tentunya jika kita mempunyai
sebuah objek yang bernilai null. Saat kita tidak menetapkannya
dengan nullable receiver type, maka kita perlu memeriksa apakah objek
tersebut bernilai null atau tidak? Bisa juga dengan menggunakan
operator safe call setiap kali extension tersebut dipanggil. Contohnya
seperti berikut:
fun main() {
println(value?.slice)
println(value1?.slice)
get() = this.div(2)
/*
output : null
null
*/
Kita juga bisa menentukan nilai dari receiver object jika bernilai null.
Sehingga kita tidak perlu lagi menggunakan operator safe call ketika
ingin memanggil extension tersebut.
fun main() {
val value: Int? = null
println(value.slice)
println(value1.slice)
get() = this?.div(2) ?: 0
/*
output : 0
*/
import packagename.ClassName
import packagename.functionName
import packagename.propertyName
import kotlin.random.Random
import kotlin.random.Random
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sqrt
fun main(){
println(PI)
println(cos(120.0))
println(sqrt(9.0))
/*
Output:
3.141592653589793
0.8141809705265618
3.0
*/
Kita juga dapat mengganti nama sebuah kelas, fungsi atau variabel
yang kita import dengan menggunakan alias yang direpresentasikan
dengan kata kunci as.
import kotlin.math.PI
fun main(){
println(PI)
println(cosinus(120.0))
println(akar(9.0))
}
/*
Output:
3.141592653589793
0.8141809705265618
3.0
*/
Kita dapat mengimpor seluruh kelas, fungsi dan variabel yang berada
pada suatu package dengan menggunakan tanda * pada
akhir package tersebut.
import kotlin.math.*
fun main(){
println(PI)
println(cos(120.0))
println(sqrt(9.0))
/*
Output:
3.141592653589793
0.8141809705265618
3.0
*/
com.dicoding.oop.utils.sayHello()
/*
Output:
*/
import com.dicoding.oop.utils.sayHello
fun main() {
sayHello()
/*
Output:
*/
Untuk dapat memahami tentang package lebih lanjut, mari kita buat
beberapa fungsi dan variabel pada package tersebut. Buka kembali
berkas MyMath.kt, tambahkan beberapa fungsi dan variabel yang akan
kita gunakan nantinya.
package com.dicoding.oop.utils
result *= number
counter--
return result
result *= counter
counter++
return result
return PI * 2 * radius
import com.dicoding.oop.utils.factorial
import com.dicoding.oop.utils.pow
import com.dicoding.oop.utils.sayHello
fun main() {
sayHello()
println(factorial(4.0))
println(pow(3.0, 2.0))
println(PI)
/*
output:
24.0
9.0
3.1415926535
*/
Pada awal kode terlihat saat kita menggunakan suatu fungsi atau
variabel yang berada pada package tertentu, kita perlu melakukan
impor pada setiap fungsi atau variabelnya. Namun, jika kita
menggunakan seluruh fungsi atau variabel dalam package tertentu kita
bisa menggunakan tanda bintang (*) untuk melakukan impor pada
seluruh fungsi dan variabel di package tersebut. Perhatikan kode
berikut.
package com.dicoding.oop
import com.dicoding.oop.utils.*
fun main() {
sayHello()
println(factorial(4.0))
println(pow(3.0, 2.0))
println(PI)
println(areaOfCircle(13.0))
/*
output:
24.0
9.0
3.1415926535
81.681408991
*/
Exception
Kode yang baik yaitu kode yang terhindar dari segala bentuk kejadian
dengan efek buruk pada aplikasi kita. Kejadian tersebut pada
programming disebut Exception. Hal terburuk yang disebabkan
oleh exception ini adalah dapat terhentinya aplikasi ketika dijalankan.
Hal seperti ini seharusnya kita hindari. Nah karena itu kita harus
mengetahui cara menangani suatu exception (Exception Handling) pada
sub-modul selanjutnya.
ArithmeticException
NumberFormatException
NullPointerException
ArithmeticException merupakan exception yang terjadi karena kita
membagi suatu bilangan dengan nilai nol. Berikut merupakan contoh
kode yang dapat membangkitkan ArithmeticException.
fun main() {
val someValue = 6
println(someValue / 0)
/*
output:
*/
/*
output:
*/
println(someMustNotNullValue)
/*
output:
*/
Exception Handling
Exception handling dapat diterapkan dengan beberapa cara. Di
antaranya adalah dengan menggunakan try-catch, try-catch-finally,
dan multiple catch. Mari kita pelajari ketiga cara tersebut.
try-catch
Salah satu cara untuk menangani suatu exception adalah
menggunakan try-catch. Kode yang dapat membangkitkan
suatu exception disimpan dalam blok try, dan jika exception tersebut
terjadi, maka blok catch akan terpanggil. Berikut cara penulisan try-
catch pada Kotlin:
try {
Dengan menuliskan kode dalam blok try, kode kita menjadi terproteksi
dari exception. Jika terjadi exception maka program tidak akan terhenti
atau crash, namun akan dilempar menuju blok catch. Di sana kita
dapat menuliskan sebuah kode alternatif untuk menampilkan pesan
eror atau yang lainnya.
fun main() {
try {
someMustNotNullValue = someNullValue!!
println(someMustNotNullValue)
println(someMustNotNullValue)
/*
output:
*/
try-catch-finally
Selain terdapat blok try dan catch, ada juga blok finally. Hanya saja
blok ini bersifat opsional. finally akan dieksekusi setelah program
keluar dari blok try ataupun catch. Bahkan finally juga tereksekusi
ketika terjadi exception yang tidak terduga. Exception tidak terduga
terjadi ketika kita
menggunakan NullPointerException pada catch namun exception yan
g terjadi adalah NumberFormatException.
try {
someMustNotNullValue = someNullValue!!
} finally {
println(someMustNotNullValue)
/*
output:
*/
finally {
// Block finally akan terpanggil setelah keluar dari block try atau catch
fun main() {
try {
someIntValue = someStringValue!!.toInt()
someIntValue = 0
someIntValue = -1
} finally {
when(someIntValue){
/*
output:
*/
12
o Primary Constructor
o ArithmeticException