پلتفرم Java SE با محیط توسعه IDE) NetBeans) ؛ (18)

در دنیای بی عیب، کاربران هرگز داده ها را به شکل غلط وارد نخواهند کرد، فایلهایی که آن ها باز می کنند همیشه وجود دارد و کد ها هرگز باگ(اشکال) ندارند. اکنون وقتش است که به مکانیزم زبان برنامه نویسی جاوا رجوع کنیم تا
يکشنبه، 4 اسفند 1392
تخمین زمان مطالعه:
موارد بیشتر برای شما
پلتفرم Java SE با محیط توسعه IDE) NetBeans) ؛ (18)

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception

 





 

Exception یا استثنا

بررسی خطا

در دنیای بی عیب، کاربران هرگز داده ها را به شکل غلط وارد نخواهند کرد، فایلهایی که آن ها باز می کنند همیشه وجود دارد و کد ها هرگز باگ(اشکال) ندارند. اکنون وقتش است که به مکانیزم زبان برنامه نویسی جاوا رجوع کنیم تا به دنیای حقیقی داده های غلط و کد های دارای باگ، رسیدگی کنیم.
مواجه شدن با خطا ناخوشایند است. اگر یک کاربر همه ی کارهایی را که در طی یک برنامه انجام داد را از دست دهد(به خاطر اشتباه برنامه نویسی یا رویداد خارجی) کاربر ممکن است برای همیشه از برنامه اش زده می شود. حد اقل شما باید:

1- آن خطا را به کاربر اطلاع دهید
2- همه ی کارها را save کنید
3- به کاربر اجازه دهید تا به خوبی از برنامه خارج شود

فرض کنید در برنامه نویسی جاوا خطاهایی در زمان اجرا رخ می دهد. این خطا ممکن است یا به خاطر فایلی که شامل اطلاعات غلط است یا به خاطر کانکشن شبکه یا استفاده از ایندکس نامعتبر آرایه و یا استفاده از یک اشاره گرکه هنوز به یک شی اختصاص داده نشده است، باشد. کاربران انتظار دارند که هنگامیکه خطا اتفاق می افتد، برنامه عملی محسوس را انجام دهد. اگر یک عملیات به خاطر یک خطا نتواند کامل شود، برنامه باید به دو صورت عمل کند که یا به یک وضعیت امن برگردد و کاربر بتواند دستور دیگری را اجرا کند و یا به کاربر اجازه دهد تا همه ی کارهایش را ذخیره کند و برنامه را خوب خاتمه دهد. انجام این کارها آسان نیست، زیرا کدی که خطا را شناسایی می کند، معمولا از کدی که می تواند داده ها را به وضعیت امن عقبگرد کند یا از کدی که کار های کاربر را save کند و به خوبی خارج شود، خیلی فرق دارد.
در شرایط استثنا، مانند داده های ورودی غلط که ممکن است برنامه crash(یک برنامه زمانى دچار این حالت مى شود که خروجى هاى ان نادرست بوده و یا به علت اشتباهات منطقى و گرامرى قابل اجرا شدن نباشد) شود، جاوا از یک غلط یابی به نام اداره کردن استثنا(exception handling)، استفاده می کند. استثنا در جاوا شبیه c++ و دلفی است.
ماموریت اداره کننده ی استثنا، انتقال کنترل از جایی که خطا اتفاق افتاده به اداره کننده ی خطا(error handler) که می تواند این وضعیت را رسیدگی کند، می باشد. برای اداره کردن شرایط استثنا در برنامه، شما باید علت خطا یا مشکلی که اتفاق می افتد را بدانید. چه مشکلاتی را باید بررسی کرد؟

1- خطاهای ورودی کاربر
2- خطا های تجهیزات
3- محدودیتهای فیزیکی
4- خطا های کد

Exceptions

وقتی یک خطا تشخیص داده می شود، یک استثنا پیش می آید. استثنا کدی است که اجرا را فورا متوقف می کند و کنترل به بخش catch مربوط به همان بلوک try انتقال پیدا می کند. بلوک try ممکن است در فانکشن جاری باشد(اونی که سبب خطا می شود) یا در بعضی از فانکشن هایی که در فانکشن جاری فراخوانی می شوند قرار گیرند(یعنی اگر فانکشن جاری برای اداره ی استثنامهیا نباشد، به زنجیر فراخوانی پاس داده می شود) اگر هیچ فانکشن فعال جاری برای catch استثنا مهیا نباشد، یک پیام خطا چاپ می شود و برنامه متوقف می شود.
استثنا می تواند توکار یا داخلی، باشد یعنی در یکی از کتابخانه های استاندارد جاوا تعریف شده باشد و یا توسط کاربر تعریف شود. در زیر تعدادی از نمونه های استثنای داخلی آورده شده است:

ArithmeticException (مثلا تقسیم بر صفر)
ClassCastException (مثلا تبدیل شی string به integer)
IndexOutOfBoundsException
NullPointerException
FileNotFoundException (مثلا باز کردن فایلی که وجود ندارد)
استثناهای checked و unchecked

exception دو نوع است، checked و unchecked . استثنا های checkedدر زمان کامپایل(Compiletime) رخ می دهند مانند IOException(یک IOtimeException برای یک چیز بد اتفاق می افتد مانند یک خطای I/O) و SQLException. در واقع این خطاها به سینتکس برنامه مربوط می شوند.به عنوان مثال بجای نوشتن main بنویسیم Main . این دسته باید حتما Handle شوند. اما استثنا های unchecked در زمان اجرا(Runtime) رخ می دهند مانند ArithmeticException ، NullPointerException و IndexOutOfBoundsException. دراین دسته برنامه بدون هیچ مشکلی کامپایل می شود اما نتایج نادرستی می دهد یا برنامه Crash می کند .اگر یک متد شامل کد هایی باشد که بتواند باعث استثنا checked شود، آنگاه دو حالت داریم:
1- روش اول: استثنا باید با استفاده از عبارت throws ، در هدر متد تعریف شود. در این روش مدیریت خطا وجود ندارد و زمانی که خطایی بوجود می آید فقط پیغام خطا چاپ می شود.
زمانیکه می دانیم در متدی استثنا رخ می دهد اما نمی خواهیم try/catch را بنویسیم، باید جلوی آن، throws Exception را بنویسیم یعنی آن را پرتاب می کنیم. سپس در متد فراخواننده ی این متد، آن را پیاده سازی کنیم. مثال زیر را در نظر بگیرید:
فرضا در کلاسی به نام example متدی به نام test داریم و نمی خواهیم درآن try/catch را پیاده سازی کنیم. اگر try/catch را در main پیاده سازی نکنیم، زمانی که می خواهیم در main متد test را فراخوانی کنیم، زمان اجرا کامپایلر پیغام خطا می دهد. بنابراین باید در متد main آن را در try/catchقرار دهیم.

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
خروجی آن به صورت زیر می باشد:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
فرض کنیم که متد test دارای خطای استثنا می باشد ودرآن try/catch پیاده سازی نشود وexception به متد فراخواننده ی آن یعنی متد main پرتاب شود(throws شود) و متد main هم آن را throws به متد بعدی throws کند اما قبل از main متد بعدی وجود ندارد و قبل از main، JVM نشسته است و JVM نمی فهمد که باید آن را handle(مدیریت) کند. و در این حالت انگار ما exception را handle نکرده ایم. در اصل این کاردرست نیست. این حالت را زمانی استفاده می کنیم که فعلا نمی خواهیم exception را مدیریت کنیم و در پایان پروژه این کار را انجام می دهیم.
2- روش دوم: کدی که ممکن است سبب استثنا شود، باید داخل بلوک try با یک عبارت catch برای استثنا قرار گیرد. (درقسمت try دستورات اصلی را می نویسید، در صورتی که این دستورات باعث ایجاد خطا شوند قسمت catch اجرا می شود) :

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
بنابراین به طور کلی، شما باید یک سری کد که امکان وقوع استثنا checked را تائید می کند، را قرار دهید. اگر این کار را انجام ندهید، خطایی را در زمان کامپایل خواهید داشت.

چگونه یک استثنا catch می شود:


پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception

• هر بخش catch نوع یک استثنا را مشخص می کند و نامی را برای آن در نظر می کیرد(مشابه هدر یک فانکشن نوع و نام یک پارامتر را تعیین می کند). استثنا های جاوا اشیا هستند، بنابراین دستورات در یک عبارت catch، می توانند به شی استثنای پیش آمده، با استفاده از نام اختصاص یافته ی آن، رجوع کند.
• عبارت Finally اختیاری است.
• به طور کلی، در آنجا می تواند یک catch یا بیشتر قرار گیرد. اگر یک عبارت Finally وجود داشته باشد، انجا می تواند عبارت catch وجود نداشته باشد.
• e که catch به عنوان پارامتر ورودی می گیرد(یا id-1 دربالا) می تواند هر چیزی باشد. مثلا می توانیم x یا y یا هر چیز دیگری بجای آن بنویسیم و در واقع آبجکتی از کلاس exception است و JVM این آبجکت را به آن پاس می دهد. مثلا اگر در قسمت catch ، در دستور system.out.println این را قرار دهیم، هنگام چاپ، کلاسی که مسئول این استثنا است و همچنین نوع خطا را درخروجی نشان می هد. مثلا هنگامی که می خواهیم 1 را بر 0 تقسیم کنیم، استثنا رخ می دهد.

به عنوان مثال، کلاسی را با کد های زیر در نظر بگیرید:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
خروجی آن به صورت زیر می باشد که در کادر قرمز، نام آن کلاس که مسئول این استثنا است آورده شده است:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
اگر ()e.getMessage را بنویسیم:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
فقط نوع خطا را می نویسد(کادر قرمزدر خروجی زیر):

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
مثال دیگر : برنامه ای که می خواهد فایلی را با استفاده ازدستور خط اول، برای خواندن باز کند:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
زمانیکه می خواهیم به کارمان سرعت بخشیم، نوع دیگری است که می توان از آن استفاده کرد(البته به آن توصیه نمی شود)و به صورت زیر می باشد که درcatch فقط دستور زیر را می نویسیم:
e.PrintStackTrace();
این نوع نمی خواهد خطا را مدیریت کند و فقط می خواهد بداند که این خطا از کجا ناشی شده و بعد از اینکه به آن پی بردید می تواید آن را پاک کنید و بجای آن همان System.out.println را در قسمت بلوکcatch بنویسید. این نوع ذکر شده تا اگر در کدی با این دستور مواجه شده اید، کارآن را بدانید.

نکات:
• برنامه باید اطمینان پیدا کند که قبل از استفاده از args[0] ، یک خط دستور آرگومان وجود دارد
• همچنین، باید اطمینان پیدا کند تا بلوک try در loopقرار گرفته ، برای اینکه اگر فایل پیدا نشد، کاربر بتواند درخواست کند تا فایل جدیدی را وارد کند و بتواند فایل جدیدی را باز کند.
• اگر کاربر برنامه را با نام فایل بی اعتبار اجرا کرد، پیام "file foo not found" چاپ شود و برنامه متوقف شود.
• بالا ترین ساختار در مبحث استثنا ها کلاس exception می باشدو این کلاس پدر همه ی کلاسهای دیگر است.
• در catch می توان دوباره try/catch نوشت.
• اگر هیچ بلوک try وجود نداشته باشد و برنامه با نام نامعتبر اجرا شود، پیام پیچیده تری ممکن است چاپ شود مثل:

java.io.FilenotFoundException: foo
at java.io.FileInputStream ...
at ...
at Test.main ...

عبارت Finally

وقتی دی کد یک استثنا اتفاق می افتد، پردازش باقی مانده ی کد در متد متوقف می شود و از آن خارج می شود. اگر متد منابع محلی در دست داشته باشد این مسئله ای است، که فقط این متد از آن اطلاع دارد و آن منبع باید آزاد شود. جاوا راه حلی برای این مورد ارائه کرده است و آن عبارت finally می باشد. در اینجا ما به شما نشان خواهیم داد که چگونه یک فایل را در جاوا ببندیم. اگر شما بخواهید برنامه نویسی پایگاه داده انجام دهید، نیاز دارید از یک چنین تکنیک برای بستن کانکشن های پایگاه داده استفاده کنید. این مهم است که هنگام وقوع استثنا، تمام کانکشن های پایگاه داده را ببندید.
خواه استثنا اتفاق بیافتدخواه نیافتد، کد درون عبارت finally اجرا می شود. در مثال زیر، همه ی حالت ها را بررسی کرده است:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
1- حالت اول: اگردر کد استثنا اتفاق نیافتد. در این مورد، برنامه ابتدا تمام کدهای درون بلوک try را اجرا می کند. سپس کد درون عبارت finally را اجرا می کند. بعد ازآن، اجرا با اولین دستور بعد از بلوک finally ادامه می یابد. به عبارت دیگر، اجرا ازمیان نقاط 1،2،5،6 عبور می کند.
2- حالت دوم: اگردر کد استثنا اتفاق بیافتد، که در بلوک catch آن را می فهمیم(در مثال ما یک IOException می باشد). برای این مورد برنامه همه ی کد های بلوک try را اجرا می کند، و به نقطه ی وقوع استثنا می رسد. و از باقی مانده ی کد در بلوک try پرش می کند. سپس برنامه کد درون catch مربوط به آن و بعد از آن، کد درون بلوک finally را اجرا می کند. اگردر بلوک catch یک استثنا اتفاق نیافتد، برنامه ابتدا خط بعد از بلوک finally را اجرا می کند. در این سناریو، اجرا از خطوط 1،3،4،5،6 عبور می کند.
3- حالت سوم: در کد استثنائی رخ دهد که در هیچ بلوک catch ای گرفته نشود. در اینجا برنامه تمام کد های درون بلوک try را اجرا می کند تا استثنا رخ دهد. سپس از باقی مانده ی کد بلوک try پرش می کند. و کد درون بلوک finally را اجرا می کند و استثنا به فراخواننده ی این متد بر می گرداننده می شود. اجرا فقط از نقاط 1،5 عبور می کند.
شما می توانید از بلوک finally، بدون بلوک catch استفاده کنید. مانند زیر:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
در بلوک try خواه با استثنا مواجه شویم خواه نشویم، دستور in.close() در بلوک finally اجرا می شود. البته اگر یک استثنا اتفاق افتد، و باید در catch دیگری گرفته شود.
ما شدیدا پیشنهاد می کنیم که از حالت try/catch و try/finally استفاده کنید. این شما را کمتر گیج می کند:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
Try داخلی وظیفه ی جداگانه دارد: این اطمینان را می دهد که input stream(جریان ورودی) بسته شده است.
Try خارجی هم وظیفه ی جداگانه ی دیگری دارد: این اطمینان را می دهد که خطاها گزارش داده شده اند. نه فقط این مسئله، بلکه خطاهای درون بلوک finally را گزارش می دهد.
وقتی یک بلوک finally شامل دستور return باشد، نتایج غیر منتظره می تواند برگرداند. فرض کنید با دستور return از وسط بلوک try خارج می شوید. قبل از خارج شدن متد، بلوک finally اجرا می شود. اگر بلوک finally هم شامل دستور return را داشته باشد، مفدار return اصلی اول ماسک می کند یا می پوشاند. مثال زیر را در نظر بگیرید:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
اگر شما f(2) را فراخوانی کنید، بلوک try r=4 محاسبه می کند و دستور return را اجرا می کند. به هرحال بلوک finally قبل از بازگشت واقعی از متد اجرا می شود و باعث می شود متد مقدار صفر را برگرداند(دستور return 0 اجرا شود). و از return 4 صرفه نظر می کند.

طبقه بندی استثنا:

در زبان برنامه نویسی جاوا، یک شی استثنا همیشه یک نمونه از یک کلاس مشتق شده از Throwable می باشد. اگر آن استثنا هایی را که در جاوا ساخته شده اند، مناسب با نیاز شما نباشد، می توانید کلاسهای استثنا خودتان را بسازید.
در تصویر زیر سلسله مراتب استثنا را در جاوا مشاهده می کنید:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
توجه کنید که همه ی استثنا ها ، THRowable را به ارث می برند، اما سلسله مراتب بدون واسطه به دو بخش تقسیم می شود: Error و Exception . سلسله مراتب Error، خطاهای داخلی و تمام شدن منابع درون سیستم زمان اجرای جاوا را توصیف می کند.
1. بیشتر استثنا ها unchecked هستند.
2. IOExceptions از دسته ی checked هستند.
3. استثنا های تعریف شده ی کاربر باید معمولا checked باشند، بنابراین آنها باید زیر کلاس Exception. باشند.
قانون عمومی این است: یک RuntimeException برای این اتفاق می افتد که شما یک خطای برنامه نویسی انجام دهید.
استثنا هایی که از RuntimeException ارث بری می کنند شامل زیر می باشند:
1- تبدیل نادرست
2- دسترسی خارج از محدوده به آرایه
3- دسترسی به اشاره گر null
استثنا هایی که از IOtimeException ارث بری می کنند شامل زیر می باشند:
1- خواندن بعد از انتهای فایل
2- باز کردن فایلی که وجود ندارد
3- جستجوی یک شی کلاس برای یک رشته که یک کلاس موجود برای آن مشخص نشده
انواع استثنا ها
تعداد انواع Exception های ممکن می تواند بیشمار باشد. که چند تا را نام می بریم:
1- NullPointerException: استثنا اشاره به تهی
کلاسی تحت عنوان NullPointerException ایجاد می کنیم. سپس در متد main این کلاس یک شی از روی کلاس string تحت عنوان str می سازیم و مقدار اولیه آن را برابر null قرار می دهیم. سپس با استفاده از متد length در دستور System.out.println(s.length()); می خواهیم تعداد کاراکترهای شی ساخته شده از روی کلاس string را شمارش کنیم.
برنامه به صورت زیر می باشد:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
سپس پروژه را اجرا می کنیم و خروجی به صورت زیر می باشد:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
همانطور که در تصویر بالا می بینید پس از اجرا با یک NullPointerException مواجه شدیم که علت آن این است که برای object های ایجاد شده از روی کلاس string باید مقداری غیر null در نظرگرفت تا اگر از متد length استفاده کردیم، این متد تعداد کاراکتر های مرتبط با شی ساخته شده را از روی کلاس string بشمارد. چون مقدار آن null است برنامه با استثنا از نوع NullPointerException مواجه خواهد شد.
2- NumberFormatException:
شی ای تحت عنوان str از روی کلاس string ایجاد می کنیم و مقدار اولیه ی آن برابر rasekhoon قرار می دهیم. سپس متغییری از نوع int با نام i ایجاد می کنیم و مقدار آن را برابر با متد parselnt() که به کلاس integer ضمیمه شده قرار می دهیم. شی ایجاد شده از روی کلاس string را به عنوان پارامتر متد parselnt در نظر می گیریم (برای تبدیل متغییر ها از کلاس ها و متد های آنها استفاده می کنیم).
برنامه به صورت زیر می باشد:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
سپس پروژه را اجرا می کنیم و خروجی به صورت زیر می باشد:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
همانطور که در تصویر بالا می بینید پس از اجرا با یک NumberFormatException مواجه شدیم که علت آن این است که نمی توانیم یک شی از نوع string را به متغیری از نوع int تبدیل کنیم.
3- ArrayIndexOutOfBoundsException :
یک آرایه از نوع int به نام x به طول 15 ایجاد می کنیم. سپس می خواهیم در خانه ی 16 آن مقدار 270 را قرار دهیم.
کدهای این برنامه به صورت زیر می باشد:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
سپس پروژه را اجرا می کنیم و خروجی به صورت زیر می باشد:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
همانطور که در تصویر بالا می بینید پس از اجرا با یک ArrayIndexOutOfBoundsException مواجه شدیم که علت آن این است که می خواستیم مقداری به یک خانه از آرایه بدهیم که خارج از محدوده ی آن بوده است.
شما می توانید با تست ایندکس آرایه در برابر محدوده ی آرایه از ArrayIndexOutOfBoundsException اجتناب کنید .

ایجاد exception سفارشی

برای این کار ابتدا کلاسی به نام Myexp می سازیم که کلاس Exception را به ارث می برد و برای آن یک سازنده تعریف می کنیم که این سازنده یک ورودی به نام e از نوع exception می گیرد. و پیغام درون سازنده ("Myexp....") زمانی بوجود می آید که در سیستم خطای استثنا بوجود آید. ما یک سازنده ی دیگر هم برای آن تعریف کردیم که پارامتر ورودی نمی گیرد و پیغام آن به صورت "Myexp .... rasekhooooooon " می باشد. به صورت زیر کد ها را می نویسیم:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
اکنون می خواهیم این exception سفارشی را استفاده کنیم. مثالی که در ابتدا زده ایم را دنبال می کنیم. در قسمت catch از کلاس exception سفارشی استفاده کرده ایم(در مورد نحوه ی استفاده ی آن در بخشهای آینده توضیح خواهیم داد)

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
وقتی این کد را در IDE وارد می کنیم می بینیم خطا دارد. این به خاطر ان است که خود خط 16 دارای خطای استثنا می باشد و برای حل این موضوع فعلا در هدر تابع main و test دستور throws Exception را قرار می دهیم(که درکد زیر برجسته شده) و کد را به صورت زیر تکمیل می کنیم:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
( البته می توانیم این کار را انجام ندهیم و دستور throws Exception را ننویسیم اما در عوض باید کلمه ی throw را قبل از Myexp بر داریم. در این حالت در خروجی آن عبارت هایی که به رنگ قرمز در خروجی نوشته شده را دیگر چاپ نمی کند.)
اگر از کدهای بالا اجرا بگیریم، و چون کلاس Myexp() با پارامتر ورودی e می باشد، سازنده ی دومی را (در کلاس سازنده ی سفارشی) فراخوانی می کند و خروجی به صورت زیر می شود:

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
و اگر Myexp() را بدون پارامتر ورودی e بنویسیم، سازنده ی اولی را (در کلاس سازنده ی سفارشی) فراخوانی می کند و اکنون خروجی به صورت زیر می شود

پلتفرم Java SE با محیط توسعه ی NetBeans(18) Exception
این عبارات چاپ شده در خروجی مربوط به خود exception می باشد(چون کلاس اصلی ما از کلاس exception ارث بری کرده است)و مهم نیست و کلیک روی آن شما را به خط مربوطه که در آنجا بوجود آمده است، می برد.
در اینجا بخش exception را به پایان می بریم.
استفاده از مطالب این مقاله با ذکر منبع راسخون بلامانع است.



 

 



مقالات مرتبط
ارسال نظر
با تشکر، نظر شما پس از بررسی و تایید در سایت قرار خواهد گرفت.
متاسفانه در برقراری ارتباط خطایی رخ داده. لطفاً دوباره تلاش کنید.