آموزش پردازش استثناها کاتلین (Kotlin) بخشی مهم از برنامهنویسی ایمن و مطمئن است که به جلوگیری از وقوع خطاهای پیشبینی نشده و مدیریت صحیح خطاها در زمان اجرا کمک میکند. این زبان از مفاهیم مشابهی با جاوا برای مدیریت استثناها استفاده میکند و تمام استثناها در کاتلین از کلاس پایه Throwable مشتق میشوند. در این مقاله به بررسی جزئیات مدیریت استثناها در کاتلین و استفاده از ساختارهای مختلف آن میپردازیم.
مدیریت استثناها
استثناها یا Exceptions در زبانهای برنامهنویسی به وقایعی گفته میشوند که در هنگام اجرای برنامه، اجرای عادی آن را مختل کرده و منجر به بروز خطا میشوند. این خطاها میتوانند ناشی از اشتباهات برنامهنویسی، مانند تقسیم عدد بر صفر، یا خطاهایی در زمان اجرا مانند دسترسی به اندیس خارج از محدوده یک آرایه، یا باز کردن فایلی که وجود ندارد باشند. مدیریت این استثناها به ما کمک میکند تا این خطاها را به شکل مناسبی شناسایی و رفع کرده و از توقف ناگهانی برنامه جلوگیری کنیم.
در این مقاله به بررسی کامل مفهوم استثناها در زبان برنامهنویسی کاتلین (Kotlin)، نحوه مدیریت و جلوگیری از وقوع خطاها با استفاده از این مفهوم، و ارائهی مثالهایی عملی برای فهم بهتر موضوع میپردازیم.
مفهوم استثناها در کاتلین
کاتلین مانند بسیاری از زبانهای برنامهنویسی، مکانیزم مدیریت استثناها را برای مدیریت خطاهای زمان اجرا ارائه میدهد. این خطاها میتوانند شامل انواع مختلفی از استثناها مانند ArithmeticException (برای تقسیم بر صفر)، ArrayIndexOutOfBoundsException (دسترسی به اندیس خارج از محدوده آرایه) و FileNotFoundException (خطا در هنگام باز کردن فایلهای ناموجود) باشند.
تمام استثناها در کاتلین از کلاس اصلی Throwable مشتق میشوند. این کلاس دو زیرکلاس اصلی دارد:
Exception: این دسته از خطاها قابل پیشبینی و مدیریت هستند و در کاتلین بهعنوان خطاهای زمان اجرا محسوب میشوند.
Error: این دسته از خطاها بیشتر به مشکلات سیستمی و جدیتر مانند کمبود حافظه مرتبط هستند و معمولاً در برنامه مدیریت نمیشوند.
انواع استثناها
1. ArithmeticException
این استثنا زمانی رخ میدهد که یک عملیات ریاضی نادرست مانند تقسیم بر صفر انجام شود.
fun main() {
try {
val result = 10 / 0
println("نتیجه: $result")
} catch (e: ArithmeticException) {
println("خطا: نمیتوان بر صفر تقسیم کرد")
}
}
در این مثال، زمانی که برنامه تلاش میکند عدد ۱۰ را بر صفر تقسیم کند، ArithmeticException رخ میدهد و با استفاده از بلوک catch مدیریت میشود.
2. NullPointerException
این استثنا زمانی رخ میدهد که برنامه سعی در دسترسی به یک مقدار null در یک متغیر داشته باشد. از آنجا که کاتلین به طور پیشفرض از Null Safety پشتیبانی میکند، معمولاً این خطا زمانی رخ میدهد که از متغیرهای Nullable استفاده شود بدون اینکه چک شوند.
fun main() {
val name: String? = null
try {
println(name!!.length)
} catch (e: NullPointerException) {
println("خطا: متغیر null نمیتواند دسترسی داشته باشد")
}
}
در این مثال، با استفاده از !!، برنامه به متغیر name دسترسی پیدا میکند، اما چون مقدار null دارد، خطای NullPointerException رخ میدهد.
3. IndexOutOfBoundsException
این استثنا زمانی رخ میدهد که برنامه سعی کند به اندیسی در آرایه یا لیست دسترسی پیدا کند که خارج از محدوده تعریف شده باشد.
fun main() {
val numbers = arrayOf(1, 2, 3)
try {
println(numbers[5])
} catch (e: ArrayIndexOutOfBoundsException) {
println("خطا: اندیس خارج از محدوده آرایه")
}
}
در این مثال، چون آرایه دارای سه عنصر است و برنامه سعی میکند به اندیس ۵ دسترسی پیدا کند، استثنای ArrayIndexOutOfBoundsException رخ میدهد.
4. NumberFormatException
این استثنا زمانی رخ میدهد که برنامه سعی در تبدیل یک رشته به یک عدد داشته باشد اما فرمت رشته با فرمت عددی سازگار نباشد.
fun main() {
try {
val number = "10a".toInt()
println("عدد: $number")
} catch (e: NumberFormatException) {
println("خطا: فرمت رشته با فرمت عددی سازگار نیست")
}
}
در این مثال، رشته “10a” نمیتواند به عدد تبدیل شود، و بنابراین خطای NumberFormatException رخ میدهد.
5. IllegalArgumentException
این استثنا زمانی رخ میدهد که یک متد ورودی نامعتبری دریافت کند که با پارامترهای قابل قبول آن متد سازگار نیست.
fun setAge(age: Int) {
if (age < 0) {
throw IllegalArgumentException("سن نمیتواند منفی باشد")
}
}
fun main() {
try {
setAge(-5)
} catch (e: IllegalArgumentException) {
println("خطا: ${e.message}")
}
}
در این مثال، چون مقدار age منفی است، متد setAge خطای IllegalArgumentException را پرتاب میکند.
6. IOException
این استثنا زمانی رخ میدهد که یک عملیات ورودی یا خروجی با شکست مواجه شود، مانند خواندن یا نوشتن در فایل.
import java.io.File
import java.io.IOException
fun readFile(filename: String) {
try {
val file = File(filename)
val content = file.readText()
println(content)
} catch (e: IOException) {
println("خطا: فایل پیدا نشد یا خوانده نشد")
}
}
fun main() {
readFile("unknown.txt")
}
در این مثال، اگر فایل unknown.txt وجود نداشته باشد، خطای IOException رخ میدهد.
7. FileNotFoundException
این استثنا زیرکلاس IOException است و زمانی رخ میدهد که برنامه سعی دارد به فایلی دسترسی پیدا کند که وجود ندارد.
import java.io.FileNotFoundException
fun readFileContent(filename: String) {
try {
val file = File(filename)
val content = file.readText()
println(content)
} catch (e: FileNotFoundException) {
println("خطا: فایل پیدا نشد")
}
}
fun main() {
readFileContent("nonexistent.txt")
}
در این مثال، اگر فایل nonexistent.txt وجود نداشته باشد، خطای FileNotFoundException رخ میدهد و در بلوک catch مدیریت میشود.
بلوکهای try-catch-finally
در کاتلین، میتوانیم با استفاده از بلوکهای try-catch استثناها را مدیریت کنیم. همچنین، بلوک finally برای اجرای کدی استفاده میشود که باید در هر شرایطی (صرف نظر از اینکه خطا رخ داده باشد یا نه) اجرا شود.
fun main() {
try {
val result = 10 / 0
println("نتیجه: $result")
} catch (e: ArithmeticException) {
println("خطا: تقسیم بر صفر")
} finally {
println("اجرای بلوک finally")
}
}
در این مثال، حتی اگر خطای تقسیم بر صفر رخ دهد، بلوک finally اجرا میشود.
استفاده از try به عنوان یک عبارت
در کاتلین، try یک عبارت است و میتواند نتیجهای بازگرداند. این ویژگی زمانی مفید است که بخواهیم یک مقدار بازگشتی داشته باشیم و در صورت بروز خطا، مقدار دیگری را برگردانیم.
fun main() {
val result = try {
"10a".toInt()
} catch (e: NumberFormatException) {
println("خطا: فرمت عددی نامعتبر")
-1
}
println("نتیجه: $result")
}
در این مثال، اگر خطا رخ دهد، مقدار -1 به متغیر result اختصاص مییابد.
ایجاد استثناهای سفارشی
در کاتلین، میتوانیم استثناهای خاص و سفارشی خود را با ارثبری از کلاس Exception تعریف کنیم. این قابلیت به ما اجازه میدهد که برای موارد خاص کسبوکار خود خطاهایی با ویژگیهای خاص تعریف کنیم.
مثال: تعریف استثنای سفارشی برای سن نامعتبر
class InvalidAgeException(message: String) : Exception(message)
fun validateUserAge(age: Int) {
if (age < 18) {
throw InvalidAgeException("سن شما کمتر از 18 سال است.")
}
}
fun main() {
try {
validateUserAge(15)
} catch (e: InvalidAgeException) {
println("خطا: ${e.message}")
}
}
در این مثال، InvalidAgeException یک استثنای سفارشی است که زمانی پرتاب میشود که سن کاربر کمتر از 18 سال باشد و پیام خطا مطابق با شرایط خاص کسبوکار چاپ میشود.
