دوره‌ها / JAVA / مدیریت استثناها/خطا (Java Exceptions)

مدیریت استثناها/خطا (Java Exceptions)

15 دقیقه Article

مدیریت استثناها (Exceptions): کدی که نمی‌شکند 🛡️🏗️

در هنگام اجرای برنامه، ممکن است با خطاهای پیش‌بینی نشده‌ای روبرو شوید (مثل تقسیم بر صفر یا نبودنِ یک فایل). بدونِ مدیریتِ صحیح، این خطاها باعث بسته شدنِ ناگهانیِ برنامه می‌شوند. در جاوا، ما از Exception Handling برای پایداریِ سیستم استفاده می‌کنیم.

۱. بلوکِ try...catch

کدهایی که احتمالِ خطا دارند را در try می‌گذاریم و نحوه‌یِ مواجهه با خطا را در catch تعریف می‌کنیم:

{code_block('try {\n int[] myNumbers = {1, 2, 3};\n System.out.println(myNumbers[10]);\n} catch (Exception e) {\n System.out.println("Something went wrong.");\n}')}

۲. بلوکِ finally 🔚

کدهای داخلِ finally در هر صورت (چه خطا رخ بدهد و چه ندهد) اجرا می‌شوند. معمولاً برای بستنِ فایل‌ها یا دیتابیس‌ها از آن استفاده می‌شود.

۳. کلمه کلیدی throw و throws 🚀

  • throw: برای پرتاب کردنِ "دستیِ" یک لرزش/خطا (مثلاً چک کردنِ سنِ کاربر).
  • throws: در امضایِ متد استفاده می‌شود تا به بقیه‌یِ برنامه‌نویسان هشدار دهد این متد ممکن است خطا بدهد.

انواعِ خطاها:

  • Checked Exceptions: توسطِ کامپایلر چک می‌شوند (مثل خطایِ خواندنِ فایل). باید حتماً مدیریت شوند.
  • Unchecked (RuntimeException): موقعِ اجرا رخ می‌دهند (مثل خطایِ ریاضی یا NullPointer).
اشتباهِ رایج: هرگز از بلاک کچِ عمومی (catch Exception e) بدونِ بررسی استفاده نکنید. سعی کنید دقیقاً بدانید چه خطایی را مدیریت می‌کنید.
نکته امنیتی: هرگز جزئیاتِ دقیقِ خطا (Stack Trace) را به کاربرِ نهایی نشان ندهید؛ این اطلاعات فقط مخصوصِ برنامه‌نویس و لاگ‌هایِ داخلی است.
<hr style="margin: 50px 0; border: 0; border-top: 1px dashed rgba(255,255,255,0.1);">

بخش تخصصی: مهندسی پیشرفته و امنیت سیستم 🛡️⚙️

در این بخش، به مفاهیمی می‌پردازیم که برای پایداری و امنیتِ برنامه‌های بزرگِ جاوا حیاتی هستند.

۱. استراتژی مدیریت استثناها (Fail-Fast vs Fail-Safe)

در طراحی سیستم‌های بزرگ، ما معمولاً از الگوی Fail-Fast استفاده می‌کنیم؛ یعنی به محض وقوع خطا، برنامه را با یک استثنای دقیق متوقف می‌کنیم تا از انتشار فساد داده‌ها جلوگیری کنیم. همچنین، نباید استثناها را با یک بلاکِ catch خالی "خفه" کنید. هر استثنا باید حتماً لاگ (Log) شود یا به لایه‌ی بالاتر گزارش داده شود.

۲. کالبدشکافی Autoboxing در حافظه

تبدیلِ اتوماتیکِ انواعِ Primitive به اشیاءِ Wrapper (مثل تبدیل int به Integer) در ظاهر ساده است، اما در حلقه‌هایِ سنگین می‌تواند باعثِ ایجادِ هزاران شیءِ اضافه در حافظه Heap و در نتیجه فشار به Garbage Collector شود. همیشه در بخش‌های حساس به پرفورمنس، از انواع Primitive استفاده کنید.

۳. پارادایم برنامه‌نویسی تابعی (Functional Programming)

استفاده از Lambda Expressions شروعِ حرکتِ جاوا به سمت برنامه‌نویسی تابعی بود. این سبک نه تنها باعثِ کوتاه‌تر شدنِ کدها می‌شود، بلکه امکانِ اجرایِ موازیِ کدها (Parallel processing) را روی پردازنده‌های چند هسته‌ای بسیار ساده‌تر می‌کند.

نکته پایانی: مهارت در مدیریتِ خطاها و استفاده از نخ‌ها (Threads)، مرزِ بین یک کدنِویسِ مبتدی و یک توسعه‌دهنده‌یِ ارشد است. همیشه کدی بنویسید که در مقابلِ بدترین ورودی‌ها هم مقاوم باشد.

تمرین‌های عملی

برای تثبیت یادگیری این درس تمرین‌های زیر را حل کنید

جلوگیری از تقسیم بر صفر Medium
سوال تمرین

یک برنامه بنویسید که در بلاکِ try، عدد 10 را بر 0 تقسیم کند. در بلاکِ catch، پیام Error occurred را چاپ کنید.

پاسخ تمرین
JAVA
public class Main {
  public static void main(String[] args) {
    try {
      int x = 10 / 0;
    } catch (ArithmeticException e) {
      System.out.println("Error occurred");
    }
  }
}

آماده رفتن به درس بعدی هستید؟

این درس را به پایان رساندید و می‌توانید به درس بعدی بروید.