Throw dan Throws — mekanisme lemparan dan deklarasi eksepsi dalam bahasa pemrograman. Operator throw menghentikan eksekusi normal fungsi dan mengirimkan objek kesalahan ke atas stack panggilan. Kata kunci throws di signature fungsi memperingatkan pihak pemanggil tentang kemungkinan kesalahan, membuat kode dapat diprediksi. Menurut Kotlin Documentation (2026), throw di Kotlin adalah ekspresi (expression), bukan instruksi, yang memungkinkan penggunaannya di dalam blok when dan operator elvis.
Hal utama
Throw — adalah operator yang menghasilkan eksepsi di titik eksekusi program. Ketika throw ditemui, aliran eksekusi saat ini segera dihentikan dan kontrol dialihkan ke penangan catch terdekat di stack panggilan. Jika penangan tidak ditemukan, aplikasi berakhir secara tidak normal. Throw dalam pengembangan mobile digunakan untuk menandakan kesalahan yang tidak dapat ditangani pada tingkat abstraksi saat ini — misalnya, respons server yang salah, tidak ada jaringan, atau argumen yang tidak valid.
Throws — pengubah di signature fungsi (terutama di Swift) yang mendeklarasikan bahwa fungsi dapat melempar kesalahan. Ini adalah bagian dari mekanisme checked errors di Swift: pihak pemanggil wajib menangani kesalahan melalui do-catch, try?, try! atau menandai fungsi mereka sendiri dengan throws untuk propagasi lebih lanjut. Di Kotlin dan Java throws juga ada, tetapi Kotlin menganggapnya berlebihan — semua eksepsi di Kotlin bersifat unchecked, artinya dapat tidak ditangani tanpa paksaan sintaksis. Menurut Apple Swift Documentation (2026), throws di Swift — satu-satunya cara untuk mendeklarasikan secara eksplisit kemungkinan kesalahan di tipe fungsi, yang membuat kontrak API transparan bagi pengembang.
Perbedaan antara throw dan throws bersifat fundamental: throw — adalah tindakan (melempar eksepsi di runtime), throws — adalah deklarasi (kontrak compile-time). Fungsi tanpa throws tidak dapat menggunakan throw — kompiler Swift akan memberikan kesalahan. Fungsi dengan throws mungkin tidak menggunakan throw — ini diizinkan tetapi tidak berarti. Pemisahan ini menjadikan throw/throws alat yang kuat dalam desain API, di mana kontrak kesalahan terlihat di signature fungsi sebelum dipanggil.
Di Swift operator throw menerima tipe apa pun yang mengimplementasikan protokol Error. Paling sering ini adalah enum dengan case untuk berbagai jenis kesalahan. Swift tidak mendukung checked exceptions gaya Java — sebagai gantinya tipe fungsi ditandai dengan throws, dan penanganan menjadi tanggung jawab pihak pemanggil. Ini membuat throw di Swift lebih fleksibel, tetapi juga lebih bertanggung jawab bagi pengembang.
Tipe apa pun yang sesuai dengan protokol Error dapat dilempar melalui throw. Paling sering pengembang menggunakan enum dengan case tanpa nilai terkait (untuk kesalahan sederhana) atau dengan associated values (untuk mengirimkan konteks). Swift tidak mewajibkan kesalahan berupa enum — struct atau class yang mengimplementasikan Error dapat digunakan, tetapi enum lebih disukai karena exhaustive switch di sisi penangan. Kompiler memeriksa bahwa semua case telah ditangani di do-catch.
enum AuthError: Error {
case invalidCredentials
case tokenExpired
case accountLocked(remainingMinutes: Int)
}
func login(username: String, password: String) throws -> Session {
guard isValid(username) else {
throw AuthError.invalidCredentials
}
let response = try api.authenticate(username, password)
if response.isLocked {
throw AuthError.accountLocked(
remainingMinutes: response.lockDuration
)
}
return Session(token: response.token)
}
AuthError mendefinisikan tiga skenario: kredensial tidak valid, token kedaluwarsa, dan akun diblokir dengan nilai terkait remainingMinutes. Fungsi login dideklarasikan sebagai throws — kompiler mengharuskan pemanggilannya melalui try. Di dalam fungsi throw digunakan di dua tempat: saat username tidak valid dan saat akun diblokir. Nilai terkait accountLocked memungkinkan penyampaian data konkret kepada pengguna — berapa menit harus menunggu hingga pembukaan blokir. Pendekatan ini menghilangkan kebutuhan akan endpoint API terpisah untuk memeriksa status pemblokiran.
Di Kotlin throw — adalah ekspresi (expression) tipe Nothing, bukan instruksi. Ini berarti throw dapat digunakan di sisi kanan penugasan, di dalam ekspresi when dan operator elvis ?:. Tipe Nothing — subtipe khusus dari semua tipe di Kotlin, yang memungkinkan penggunaan throw di tempat yang memerlukan nilai dari tipe apa pun. Kompiler memahami bahwa setelah throw eksekusi tidak berlanjut dan tidak memerlukan cabang untuk kasus ini.
Nothing — tipe unik di Kotlin yang merupakan subtipe dari semua tipe yang mungkin. Fungsi yang mengembalikan Nothing (misalnya TODO()) tidak pernah berakhir secara normal — baik selalu melempar eksepsi atau masuk ke loop tak terbatas. Ini menjadikan throw kandidat alami untuk digunakan di tempat yang memerlukan nilai: operator elvis, when tanpa else, inisialisasi variabel. Jika throw berada di cabang when, kompiler memahami bahwa cabang mengarah ke Nothing dan tidak memerlukan return atau else untuk cabang ini.
data class Config(val apiUrl: String, val timeoutSec: Int)
class ConfigParser {
fun parse(json: String): Config {
val obj = JSONObject(json)
val url = obj.optString("apiUrl")
?: throw IllegalArgumentException("apiUrl is required")
val timeout = obj.optInt("timeoutSec", 30)
return Config(url, timeout)
}
fun getErrorMessage(code: Int): String {
return when (code) {
404 -> "Not found"
500 -> "Server error"
else -> throw IllegalArgumentException("Unknown code: $code")
}
}
}
Dalam contoh pertama throw digunakan di operator elvis ?:: jika bidang apiUrl tidak ada di JSON, ekspresi throw segera menghentikan eksekusi dan melempar IllegalArgumentException. Tipe Nothing memungkinkan kompiler menyimpulkan tipe sisi kanan sebagai String (elvis mengharapkan String, throw memiliki tipe Nothing, Nothing adalah subtipe String). Dalam contoh kedua throw di dalam ekspresi when: jika kode tidak sesuai dengan salah satu yang dikenal, eksepsi dilempar. Kompiler memahami bahwa setelah throw kode tidak dapat dijangkau, sehingga tipe kembalian fungsi String tidak dilanggar.
Di Swift throws ditentukan setelah daftar parameter dan sebelum panah tipe kembalian. Fungsi dengan throws hanya dapat memanggil fungsi throws lain di dalam do-catch atau dengan try?. Jika fungsi throws tidak menangani kesalahan, ia mengirimkannya ke pihak pemanggil. Swift juga mendukung rethrows — pengubah untuk fungsi tingkat tinggi yang menerima closure dengan throws dan menyebarkan kesalahannya. Rethrows berarti fungsi hanya melempar kesalahan jika closure yang dikirim melemparkannya — fungsi itu sendiri tidak menghasilkan kesalahan.
func mapValues<T>(
_ array: [T],
transform: (T) throws -> U
) rethrows -> [U] {
var result = [U]()
for element in array {
result.append(try transform(element))
}
return result
}
// Penggunaan dengan closure throws
let parsed = try mapValues(jsonStrings) { str in
let data = Data(str.utf8)
return try JSONDecoder().decode(Item.self, from: data)
}
Rethrows memungkinkan fungsi mapValues menjadi fleksibel: ia menerima closure throws maupun biasa. Jika closure throws dikirimkan, pemanggilan mapValues memerlukan try; jika biasa — try tidak diperlukan. Ini menjadikan rethrows ideal untuk fungsi tingkat tinggi seperti map, filter, reduce di pustaka standar Swift. Rekomendasi Apple: gunakan rethrows untuk API yang menerima closure throws dan satu-satunya sumber kesalahan adalah closure tersebut. Jika fungsi dapat melempar kesalahannya sendiri, gunakan throws.
Swift throws lebih dekat ke checked exceptions (seperti di Java) — kesalahan yang dilempar dideklarasikan di signature. Kotlin dan Dart menggunakan eksepsi unchecked — throws di signature tidak diperlukan. Perbedaannya mendasar: checked memaksa pengembang untuk menangani (lebih aman tetapi lebih verbose), unchecked memberikan kebebasan tetapi meningkatkan risiko lupa menangani kesalahan. Swift memilih checked untuk throws, Kotlin — unchecked untuk semua eksepsi. Kedua pendekatan memiliki kelebihan: Swift lebih andal di tingkat bahasa, Kotlin lebih ringkas dan nyaman dalam rantai transformasi fungsional.
Untuk penanganan kesalahan terstruktur di aplikasi mobile, disarankan membuat tipe kesalahan sendiri alih-alih menggunakan Exception atau Error dasar. Di Swift untuk ini digunakan enum dengan protokol Error, di Kotlin — sealed class dengan pewarisan dari Throwable (atau dari Exception), di Dart — class dengan pewarisan dari Exception. Tipe kustom memungkinkan pengelompokan kesalahan berdasarkan kategori dan pengiriman data terkait.
| Bahasa | Tipe kesalahan | Fitur |
|---|---|---|
| Swift | enum: Error { ... } | Nilai terkait, exhaustive switch di catch |
| Kotlin | sealed class : Throwable() | Data class untuk kesalahan dengan bidang, ekspresi when |
| Dart | class implements Exception | Bidang Message, klausa on di catch |
| Java | class extends Exception | Checked vs unchecked, throws wajib di signature |
Saat mendesain kesalahan kustom ikuti aturan: satu kesalahan — satu skenario. Jangan menggabungkan penyebab berbeda dalam satu tipe dengan flag String message — buat case/subkelas terpisah untuk setiap skenario. Ini akan memungkinkan pihak pemanggil menangani setiap kasus melalui pattern matching (when/switch), bukan melalui perbandingan string. Di Swift ini memberikan exhaustive checking — kompiler akan memperingatkan jika suatu case dari enum NetworkError tidak ditangani.
sealed class NetworkError(val message: String) : Throwable(message) {
data class Timeout(val durationMs: Long) :
NetworkError("Request timed out after ${durationMs}ms")
data class HttpError(val code: Int, val body: String?) :
NetworkError("HTTP $code")
data class NoConnection(val cause: IOException) :
NetworkError("No internet connection")
}
Sealed class NetworkError mewarisi Throwable (tipe standar eksepsi di Kotlin). Setiap subkelas adalah data class dengan bidangnya sendiri: Timeout berisi durasi timeout dalam milidetik, HttpError — kode dan body respons, NoConnection — IOException asli. Desain semacam itu memungkinkan penanganan setiap kesalahan melalui when dengan cakupan menyeluruh (ketika Anda menambahkan subkelas baru, kompiler akan memaksa Anda memperbarui semua ekspresi when).
Swift menawarkan tiga varian pemanggilan fungsi throws, masing-masing dengan kontrak keamanannya sendiri. try — cara standar: memerlukan do-catch atau berada di dalam fungsi throws. try? mengubah kesalahan menjadi nil — hasil menjadi opsional, saat kesalahan nil dikembalikan, tipe berubah dari T menjadi T?. try! — eksekusi paksa tanpa penanganan: jika kesalahan dilempar, aplikasi crash. Gunakan try! hanya ketika Anda benar-benar yakin kesalahan tidak mungkin terjadi (misalnya, data yang jelas benar).
let configPath = Bundle.main.path(forResource: "config", ofType: "json")!
// try? — hasil opsional
let data = try? Data(contentsOf: URL(fileURLWithPath: configPath))
let json = try? JSONSerialization.jsonObject(with: data ?? Data())
// try! — kesuksesan terjamin (hanya saat yakin)
let decoder = JSONDecoder()
let defaultConfig = try! decoder.decode(
Config.self,
from: Config.defaultJSON
)
// try — penanganan standar
do {
let user = try fetchUser()
showUser(user)
} catch let error as NetworkError {
showRetryAlert(error.message)
}
Dalam contoh try! digunakan untuk JSON yang jelas valid yang tertanam di bundle aplikasi — kesalahan decoding tidak mungkin terjadi pada rilis yang benar. try? diterapkan untuk membaca file konfigurasi — jika file tidak ada atau rusak, aplikasi menggunakan nilai default, bukan crash. try di do-catch digunakan untuk permintaan jaringan, di mana kesalahan diharapkan dan memerlukan reaksi pengguna. Rekomendasi: hindari try! di kode produksi — kecualikan hanya untuk data konstan yang diverifikasi pada tahap build.
Pertanyaan yang sering diajukan
Throw — operator yang melempar kesalahan selama eksekusi program, menghentikan aliran. Throws — pengubah signature fungsi yang mendeklarasikan bahwa fungsi dapat melempar kesalahan. Fungsi tanpa throws tidak dapat menggunakan throw. Throws adalah kontrak compile-time, throw adalah tindakan runtime.
Kotlin mengikuti filosofi unchecked exceptions: semua eksepsi dapat tidak ditangani tanpa paksaan sintaksis. Pengembang Kotlin berpendapat bahwa throws di Java menyebabkan blok try-catch yang berlebihan dan pengabaian checked exceptions melalui catch kosong. Tipe Nothing Kotlin memungkinkan penggunaan throw sebagai ekspresi, menggantikan throws dengan cara yang lebih fleksibel.
try! hanya diizinkan ketika Anda benar-benar yakin kesalahan tidak mungkin terjadi: JSON yang jelas valid dari bundle, data konstan, skema URL yang benar. Di kode produksi try! adalah pengecualian, bukan aturan. try? lebih disukai untuk skenario opsional dengan nilai default, try dengan do-catch untuk penanganan kesalahan wajib.
Rethrows — pengubah untuk fungsi yang menerima closure throws. Fungsi dengan rethrows hanya melempar kesalahan jika closure yang dikirim melemparkannya. Ini memungkinkan fungsi tingkat tinggi (map, filter) bekerja dengan closure throws dan non-throws tanpa try paksa di pihak pemanggil.
Ya, di dalam catch throw dapat digunakan untuk menyebarkan kesalahan ke atas stack, membungkusnya dalam tipe lain atau menambahkan konteks. Ini disebut error chaining atau rethrow. Di Swift throw lain di dalam catch sudah cukup, di Kotlin — throw di dalam blok catch. Blok finally akan dieksekusi sebelum kontrol diteruskan lebih lanjut.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga