Java Exception Handling: try-catch-finally และ Custom Exception

#java13 เม.ย. 2569

Exception คืออะไร

Exception คือ event ที่เกิดขึ้นระหว่าง runtime ที่ทำให้โปรแกรมทำงานผิดปกติ Java มี exception hierarchy ที่ชัดเจน

Exception Hierarchy

Throwable
├── Error (ไม่ควร catch)
│   ├── OutOfMemoryError
│   └── StackOverflowError
└── Exception
    ├── RuntimeException (Unchecked)
    │   ├── NullPointerException
    │   ├── ArrayIndexOutOfBoundsException
    │   └── IllegalArgumentException
    └── IOException (Checked)
        ├── FileNotFoundException
        └── SQLException

try-catch-finally

try {
    int result = 10 / 0;  // ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("หารด้วยศูนย์: " + e.getMessage());
} catch (Exception e) {
    System.out.println("Error อื่น: " + e.getMessage());
} finally {
    System.out.println("รันเสมอ ไม่ว่าจะเกิด exception หรือไม่");
}

Multi-catch (Java 7+)

try {
    // code
} catch (IOException | SQLException e) {
    System.out.println("IO หรือ SQL error: " + e.getMessage());
}

try-with-resources

// ปิด resource อัตโนมัติ
try (FileReader reader = new FileReader("file.txt");
     BufferedReader br = new BufferedReader(reader)) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}
// reader และ br ถูกปิดอัตโนมัติ

Custom Exception

// Checked Exception
public class InsufficientFundsException extends Exception {
    private double amount;

    public InsufficientFundsException(double amount) {
        super("ยอดเงินไม่เพียงพอ ขาดอีก: " + amount + " บาท");
        this.amount = amount;
    }

    public double getAmount() { return amount; }
}

// Unchecked Exception
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(int userId) {
        super("ไม่พบ user id: " + userId);
    }
}

// ใช้งาน
public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException(amount - balance);
    }
    balance -= amount;
}

Exception Chaining

try {
    // database operation
} catch (SQLException e) {
    throw new ServiceException("ไม่สามารถดึงข้อมูลได้", e);
}

// ServiceException
public class ServiceException extends RuntimeException {
    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }
}

Best Practices

// ✅ Catch specific exceptions
catch (FileNotFoundException e) { ... }

// ❌ อย่า catch Exception ทั่วไปโดยไม่จำเป็น
catch (Exception e) { /* ไม่ดี */ }

// ✅ Log exception
catch (IOException e) {
    logger.error("ไม่สามารถอ่านไฟล์ได้", e);
    throw new ServiceException("อ่านไฟล์ล้มเหลว", e);
}

// ❌ อย่า swallow exception
catch (Exception e) { /* ว่างเปล่า - ไม่ดีมาก */ }

สรุป

การจัดการ exception ที่ดีช่วยให้ app มีความ robust ใช้ custom exception เพื่อให้ error message ชัดเจน และใช้ try-with-resources เพื่อป้องกัน resource leak ครับ