- İstisnanın ne olduğunu açıklamak ve yığın izini okumak
try,catchvefinallybloklarını kullanmak- Denetlenen ve denetlenmeyen istisnaları ayırt etmek ve özel bir istisna sınıfı yazmak
Kullanıcı yaşı yerine “abc” yazdı, bir dosya silindi, internet kesildi... Gerçek programlarda her şey plana göre gitmez. İyi bir program böyle durumlarda “çökmez”; sorunu kibarca bildirir ve çalışmaya devam eder. Java'da beklenmedik durumlar istisnalarla (exceptions) yönetilir.
İstisna nedir?
İstisna, programın normal akışını bozan bir olayı tanımlayan bir nesnedir. Böyle bir olay gerçekleştiğinde Java istisnayı “fırlatır” (throw): o anki metot hemen durur ve istisna, onu yakalayan bir kod bulunana kadar çağrı zinciri boyunca yukarı çıkar. Kimse yakalamazsa program durur ve konsola bir yığın izi (stack trace) yazdırılır.
public class Main {
public static void main(String[] args) {
int[] marks = {5, 4, 3};
System.out.println("Start");
System.out.println(marks[5]);
System.out.println("End");
}
}Start Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3 at Main.main(Main.java:5)
Yığın izini yukarıdan aşağıya oku: önce istisnanın türü (ArrayIndexOutOfBoundsException), sonra mesajı (5. indeks, 3 uzunluğundaki dizinin dışında), ardından nerede gerçekleştiği: Main.java dosyasının 5. satırı. “End” yazdırılmadı: bir istisnadan sonra metodun geri kalanı çalışmaz.
try, catch ve finally
Riskli kodu bir try bloğuna koyarız. Bir istisna oluşursa kontrol, uygun türdeki catch bloğuna geçer. finally bloğu ise her durumda, istisna olsa da olmasa da çalışır; genellikle bir dosyayı ya da bağlantıyı kapatmak gibi “toparlama” işleri için kullanılır.
public class Main {
public static void main(String[] args) {
String[] inputs = {"42", "abc", "0"};
for (String input : inputs) {
try {
int n = Integer.parseInt(input);
System.out.println("100 / " + n + " = " + (100 / n));
} catch (NumberFormatException e) {
System.out.println("Not a number: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Math error: " + e.getMessage());
} finally {
System.out.println("-- checked \"" + input + "\"");
}
}
}
}100 / 42 = 2 -- checked "42" Not a number: For input string: "abc" -- checked "abc" Math error: / by zero -- checked "0"
Integer.parseInt("abc")metni sayıya çeviremez veNumberFormatExceptionfırlatır.- Bir tam sayıyı sıfıra bölmek
ArithmeticExceptionoluşturur. (İlginçtir ki100.0 / 0istisna fırlatmaz veInfinityverir.) e.getMessage()istisnanın mesajını döndürür. Program istisnadan sonra durmadı; döngü bir sonraki değerle devam etti.finallyüç durumda da çalıştı.
Denetlenen ve denetlenmeyen istisnalar
Tüm istisnaların ortak atası Throwable'dır. Ondan Error (belleğin tükenmesi gibi ciddi JVM sorunları; bunlar genellikle yakalanmaz) ve Exception türer. Exception'ın da özel bir kolu vardır: RuntimeException. Bu ayrım, Java'ya özgü bir kuralı belirler:
| Özellik | Denetlenen (checked) | Denetlenmeyen (unchecked) |
|---|---|---|
| Türediği sınıf | Exception (ama RuntimeException değil) | RuntimeException |
| Derleyici zorunlu tutar mı? | evet: yakala ya da throws ile bildir | hayır |
| Genellikle anlamı | programın denetimi dışında bir sorun | bir programlama hatası |
| Örnekler | IOException, FileNotFoundException | NullPointerException, ArithmeticException, IllegalArgumentException |
Örneğin new FileReader("data.txt") yazıp onu try içine almazsan kod derlenmez: unreported exception FileNotFoundException; must be caught or declared to be thrown. Derleyici sanki şöyle der: “Dosya olmayabilir; bu durumda ne yapacağına önceden karar ver.”
throw, throws ve kendi istisnaların
Bir istisnayı kendin de fırlatabilirsin: throw new IllegalArgumentException("..."). Bu, bir metodun hatalı veri kabul etmesini önlemenin en iyi yoludur. Kendi istisna sınıfını oluşturmak için Exception (denetlenen) ya da RuntimeException (denetlenmeyen) sınıfından türet. Denetlenen bir istisna fırlatan metot bunu başlığında throws ile bildirmelidir.
public class Main {
static void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Invalid age: " + age);
}
System.out.println("Age set to " + age);
}
public static void main(String[] args) {
try {
setAge(25);
setAge(-3);
setAge(40);
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
System.out.println("Program continues");
}
}Age set to 25 Error: Invalid age: -3 Program continues
setAge(40) hiç çağrılmadı: setAge(-3) istisna fırlatır fırlatmaz try bloğu durdu ve kontrol catch'e geçti. Şimdi de kendi denetlenen istisnamızı oluşturalım; cüzdanda yeterli para olmadığı durum için:
public class Main {
public static void main(String[] args) {
Wallet wallet = new Wallet(30);
try {
wallet.pay(12);
wallet.pay(25);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
System.out.println("Missing: " + e.getMissing() + " AZN");
}
}
}
class InsufficientFundsException extends Exception {
private final double missing;
InsufficientFundsException(double missing) {
super("Not enough money in the wallet");
this.missing = missing;
}
double getMissing() { return missing; }
}
class Wallet {
private double balance;
Wallet(double balance) { this.balance = balance; }
void pay(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount - balance);
}
balance -= amount;
System.out.println("Paid " + amount + ", left " + balance);
}
}Paid 12.0, left 18.0 Not enough money in the wallet Missing: 7.0 AZN
Önemli noktalar
- İstisna, normal akışı bozan bir olaydır; yakalanmazsa program durur ve yığın izi yazdırılır.
tryriskli kodu içerir,catchbelirli türde bir istisnayı yakalar,finallyise her zaman çalışır.- Denetlenen istisnalar (
IOException) yakalanmalı ya dathrowsile bildirilmelidir;RuntimeExceptionalt sınıfları denetlenmez. throw new ...bir istisna fırlatır; kendi istisnan içinExceptionya daRuntimeException'dan türet.- Boş bir
catchbloğu yazma; hatayla ilgili bilgi kaybolur.
Kendini test et
10 soru. Her doğru cevap XP kazandırır.
finally bloğu ne zaman çalışır?