دستور try و catch

می‌توان خطاها را با استفاده از دستور try…catch اداره کرد. بدین صورت که کدی را که احتمال می‌دهید ایجاد خطا کند در داخل بلوک try قرار می‌دهید. بلوک catch هم شامل کدهایی است که وقتی اجرا می‌شوند که برنامه با خطا مواجه شود. تعریف ساده‌ی این دو بلوک به این صورت است که بلوک try سعی می‌کند که دستورات را اجرا کند و اگر در بین دستورات خطایی وجود داشته باشد برنامه دستورات مربوط به بخش catch را انجام می‌دهد. برنامه زیر نحوه استفاده از دستور try…catch را نمایش می‌دهد :

  1: fun main(args: Array<String>)
  2: {
  3:     val result: Int
  4:     val x = 5
  5:     val y = 0
  6: 
  7:     try                                                   
  8:     {                                                     
  9:         result = x / y //ERROR                                       
 10:     }                                                     
 11:     catch (e: ArithmeticException)                        
 12:     {                                                     
 13:         println("An attempt to divide by 0 was detected.")
 14:     }                                                     
 15: }
An attempt to divide by 0 was detected.

در داخل بلوک try، مقدار x را که 5 است بر y که مقدار آن 0 است تقسیم کرده‌ایم. نتیجه محاسبه به وجود آمدن خطای / by zero (عدد تقسیم بر صفر) است. از آنجاییکه در برنامه بالا خطایی به وجود آمده است کدهای داخل بلوک catch اجرا می‌شوند. بنابراین :

try 
{
    result = x / y //Error: Jump to catch block
    println("This line will not be executed.")
} 
catch (e: ArithmeticException) 
{
    println("An attempt to divide by 0 was detected.")
}

همانطور که در مثال بالا مشاهده می‌کنید از یک نوع استثناء مخصوص به یک خطا در داخل بلوک catch که کلاس ArithmeticException است استفاده کرده‌ایم. همچنین می‌توانید مقدار استثنا را در داخل یک متغیر قرار داده و سپس آن را نمایش دهید:

try
{
    result = x / y //ERROR
} 
catch (error: ArithmeticException)
{
    println(error.message)
}
/ by zero

متغیر دارای اطلاعات مفیدی در مورد استثناء به وجود آمده است. برای نمایش اطلاعاتی در مورد استثناء هم از خاصیت message استفاده می‌کنیم. همه کلاسهای استثناء توضیحاتی در مورد خطاها می‌دهند. در درسهای آینده در مورد خصوصیات استثناءها بیشتر توضیح می‌دهیم. اگر فکر می‌کنید که در بلوک try ممکن است با چندین خطا مواجه شوید می‌توانید از چندین بلوک catch استفاده نمایید ولی به یاد داشته باشید که برای هر کدام از آن خطاها از کلاس استثناء مربوط به هر یک استفاده کنید:

var result: Int
var x: Int = 5
var y: Int

try
{
    y = readLine()!!.toInt()
    result = x / y //ERROR
}
catch (error: ArithmeticException)
{
    println(error.message)
}
catch (error: NumberFormatException)
{
    println(error.message)
}

از انجاییکه مقدار y به وسیله ورودی که از کاربر گرفته می‌شود، تعیین می‌شود، مقدار آن باید با توجه به مثال بالا غیر صفر باشد (عدد تقسیم بر صفر تعریف نشده است). اما یک مشکل وجود دارد. چون ممکن است که کاربر یک مقدار غیر عددی وارد کند (مثلاً یک حرف) که در این صورت برنامه نمی‌تواند حرف را به عدد تبدیل کند و خطای نوع (NumberFormatException) اتفاق می افتد. وقتی استثناء اتفاق افتاد بلوک catch مربوط به این خطا اجرا می‌شود و محاسبه خارج قسمت تقسیم x بر y نادیده گرفته می‌شود. قسمت catch کد بالا را به صورت زیر هم می‌توان نوشت :

catch (error: Exception) 
{
    when (error) 
    {
        is ArithmeticException, is NumberFormatException -> 
        {
            println(error.message)
        }
        else -> throw error
    }
}

حال فرض کنید شما می‌خواهید تمام خطاهای احتمالی که ممکن است در داخل بلوک try اتفاق می افتند را فهمیده و اداره کنید این کار چگونه امکانپذیر است؟ به راحتی و با استفاده از کلاس عمومی Exception می‌توانید این کار را انجام داد. هر کلاس استثناء در Kotlin از این کلاس ارث بری می‌کند بنابراین شما می‌توانید هر نوع استثناءیی را در شیی از کلاس Exception ذخیره نمایید.

try
{
    //Put your codes to test here
}
catch (error: Exception)
{
    println(error.message)
}

با استفاده از این روش دیگر لازم نیست نگران اتفاق خطاهای احتمالی باشید چون بلوک catch برای هر گونه خطایی که در داخل بلوک try تشخیص داده شود پیغام مناسبی نشان می‌دهد. به این نکته توجه کنید که اگر بخواهید از کلاس پایه Exception همراه با سایر کلاسهای استثناء دیگر که از آن مشتق می‌شوند در برنامه استفاده کنید باید کلاس پایه Exception در آخرین بلوک catch قرار گیرد.

try 
{
    //Put your codes to test here
} 
catch (e: ArithmeticException) 
{
    println("Division by zero is not allowed.")
} 
catch (e: NumberFormatException) 
{
    println("Error on converting the data to proper type.")
} 
catch (e: Exception)             
{                               
    println("An error occured.")
}                               

اگر کلاس پایه Exception را در اولین بلوک catch قرار دهیم و خطایی در برنامه رخ دهد چون تمام کلاسهای استثناء از این کلاس مشتق می‌شوند در نتیجه اولین بلوک catch اجرا شده و سایر بلوک‌ها حتی با وجود اینکه خطای مورد نظر به آنها مربوط باشد اجرا نمی‌شوند.