زبان برنامهنویسی Java برای مدیریت خطاها و سایر رویدادهای استثنایی از استثناها استفاده میکند.
استثنا رویدادی است که در حین اجرای یک برنامه رخ میدهد و جریان عادی دستورها را مختل میکند. استثناها در Java بهصورت صریح ایجاد میشوند و به عمل ایجاد یک استثنا، پرتاب استثنا میگویند. به عمل مدیریت یک استثنا، گرفتن استثنا میگویند.
در Java، همهی استثناها زیرکلاسهای کلاس Exception هستند که خودش زیرکلاسی از Throwable است.
Java دو نوع استثنا را از هم تفکیک میکند:
استثناهای بررسیشده شرایط استثناییای هستند که یک برنامه باید آنها را پیشبینی کند و از آنها بازیابی کند. مثالی از یک استثنای بررسیشده، FileNotFoundException است که زمانی رخ میدهد که متدی تلاش میکند فایلی را بخواند که وجود ندارد.
این نوع استثنا در زمان کامپایل بررسی میشود: متدهایی که استثناهای بررسیشده پرتاب میکنند باید این موضوع را در امضای متد خود مشخص کنند و کدی که متدی را فراخوانی میکند که ممکن است استثنای بررسیشدهای پرتاب کند، موظف است آن را مدیریت کند. در غیر این صورت، کد کامپایل نمیشود.
همهی استثناهای بررسیشده زیرکلاسهای Exception هستند که از RuntimeException ارث نمیبرند.
استثناهای بررسینشده شرایط استثناییای هستند که یک برنامه معمولاً نمیتواند آنها را پیشبینی کند یا از آنها بازیابی کند. مثالی از یک استثنای بررسینشده، NullPointerException است که زمانی رخ میدهد که متدی که انتظار مقداری غیر از null را دارد، null دریافت میکند.
این نوع استثنا در زمان کامپایل بررسی نمیشود: متدهایی که استثناهای بررسینشده پرتاب میکنند لازم نیست این موضوع را در امضای متد خود مشخص کنند. همچنین کدی که متدی را فراخوانی میکند که ممکن است استثنای بررسینشدهای پرتاب کند، لازم نیست آن را مدیریت کند.
همهی استثناهای بررسینشده از RuntimeException ارث میبرند که خودش زیرکلاس Exception است.
یک متد در Java میتواند با استفاده از دستور throw یک استثنا پرتاب کند.
وقتی یک استثنای بررسیشده از یک متد پرتاب میشود، لازم است این موضوع در امضای متد با استفاده از کلیدواژهی throws مشخص شود، همانطور که در مثال زیر نشان داده شده است. این کار، کد فراخوانیکننده را وادار میکند پیشبینی کند که ممکن است استثنایی پرتاب شود و آن را بهطور مناسب مدیریت کند.
public class InsufficientBalanceException extends Exception {
}
public class BankAccount {
public void withdraw(double amount) throws InsufficientBalanceException {
if (balance < amount) {
throw new InsufficientBalanceException();
}
// rest of the method implementation
}
}
وقتی یک استثنای بررسینشده از یک متد پرتاب میشود، لازم نیست این موضوع در امضای متد مشخص شود، هرچند پشتیبانی میشود.
public class BankAccount {
public void withdraw(double amount) {
if (amount < 0) {
throw new IllegalArgumentException("Cannot withdraw a negative amount");
}
// rest of the method implementation
}
}
مدیریت استثناها در Java با کلیدواژههای try، catch و finally انجام میشود.
try قرار گیرند.try، یک یا چند بلوک catch میآید که استثناهای پرتابشده در بلوک try را میگیرند.catch بهصورت اختیاری یک بلوک finally میآید که همیشه بعد از بلوک try اجرا میشود، صرفنظر از اینکه استثنایی پرتاب شده باشد یا نه.مثال زیر نشان میدهد که این کلیدواژهها چگونه کار میکنند:
public class ATM {
public void withdraw(BankAccount bankAccount, double amount) {
try {
System.out.println("Withdrawing " + amount);
bankAccount.withdraw(amount);
System.out.println("Withdrawal succeeded");
} catch (InsufficientBalanceException) {
System.out.println("Withdrawal failed: insufficient balance");
} catch (RuntimeException e) {
System.out.println("Withdrawal failed: " + e.getMessage());
} finally {
System.out.println("Current balance: " + bankAccount.getBalance());
}
}
}
در این مثال، وقتی استثنایی پرتاب نمیشود، خروجی زیر چاپ میشود:
Withdrawing 10.0
Withdrawal succeeded
Current balance: 5.0
اما اگر دستور bankAccount.withdraw(amount) یک InsufficientBalanceException پرتاب کند، خروجی زیر چاپ میشود:
Withdrawing 10.0
Withdrawal failed: insufficient balance
Current balance: 5.0
یا اگر bankAccount.withdraw(amount) یک استثنای بررسینشده پرتاب کند، خروجی زیر چاپ میشود:
Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0
Java همچنین دستهی جداگانهای به نام خطاها دارد. اینها مشکلات جدیای هستند که منشأ آنها خارج از برنامه است. مثالی از یک خطا، OutOfMemoryError است که زمانی رخ میدهد که یک برنامه بخواهد از حافظهای بیشتر از آنچه در سیستم موجود است استفاده کند.
خطاها هم مانند استثناهای بررسینشده در زمان کامپایل بررسی نمیشوند. تفاوت در این است که آنها نشاندهندهی مشکلات سطح سیستم هستند و معمولاً توسط ماشین مجازی Java یا محیط، بهجای خود برنامه، پرتاب میشوند. برنامهها معمولاً نباید تلاش کنند آنها را بگیرند یا مدیریت کنند.
همهی خطاها در Java از کلاس Error ارث میبرند.
همانطور که پیشتر گفته شد، استثناها رویدادهایی هستند که جریان عادی دستورها را مختل میکنند و برای مدیریت رویدادهای استثنایی به کار میروند. بنابراین استفاده از استثناها برای کنترل جریان در برنامهی شما توصیه نمیشود.