Xử lý Ngoại lệ trong Java
Exception handling giúp chương trình xử lý lỗi một cách graceful thay vì crash. Hãy cùng tìm hiểu try-catch blocks và custom exceptions!
1. Try-Catch Cơ bản
Cú pháp cơ bản để bắt và xử lý exceptions:
public class ExceptionExample {
public static void main(String[] args) {
try {
int result = 10 / 0; // ArithmeticException
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("Không thể chia cho 0!");
e.printStackTrace();
}
System.out.println("Chương trình tiếp tục...");
}
}
2. Multiple Catch Blocks
Bắt nhiều loại exception khác nhau:
public void readFile(String filename) {
try {
FileReader file = new FileReader(filename);
BufferedReader reader = new BufferedReader(file);
String line = reader.readLine();
int number = Integer.parseInt(line);
reader.close();
} catch (FileNotFoundException e) {
System.out.println("File không tồn tại: " + filename);
} catch (IOException e) {
System.out.println("Lỗi đọc file: " + e.getMessage());
} catch (NumberFormatException e) {
System.out.println("Dữ liệu không phải số!");
} catch (Exception e) {
// Catch-all cho các exception khác
System.out.println("Lỗi không xác định: " + e);
}
}
// Java 7+: Multi-catch
try {
// some code
} catch (IOException | SQLException e) {
System.out.println("Lỗi IO hoặc SQL: " + e);
}
3. Finally Block
Code trong finally luôn chạy, bất kể có exception hay không:
public void processFile(String filename) {
FileReader file = null;
try {
file = new FileReader(filename);
// Process file...
} catch (IOException e) {
System.out.println("Lỗi: " + e.getMessage());
} finally {
// Luôn chạy - cleanup resources
if (file != null) {
try {
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("Finally block executed");
}
}
// Try-with-resources (Java 7+) - tốt hơn
public void processFileModern(String filename) {
try (FileReader file = new FileReader(filename);
BufferedReader reader = new BufferedReader(file)) {
// Process...
// Tự động close() trong finally
} catch (IOException e) {
System.out.println("Lỗi: " + e.getMessage());
}
}
4. Checked vs Unchecked Exceptions
// Checked Exception - phải xử lý hoặc throws
public void readFile(String path) throws IOException {
FileReader file = new FileReader(path); // IOException
// ...
}
// Unchecked Exception - không bắt buộc xử lý
public void divide(int a, int b) {
int result = a / b; // ArithmeticException (unchecked)
}
// Common checked exceptions:
// - IOException
// - SQLException
// - ClassNotFoundException
// Common unchecked exceptions:
// - NullPointerException
// - ArrayIndexOutOfBoundsException
// - IllegalArgumentException
// - ArithmeticException
5. Throws và Throw
Ném exception lên method gọi nó:
// throws - khai báo method có thể ném exception
public void validateAge(int age) throws IllegalArgumentException {
if (age < 0 || age > 150) {
// throw - ném exception
throw new IllegalArgumentException("Tuổi không hợp lệ: " + age);
}
}
// Sử dụng
try {
validateAge(-5);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
// Có thể throws nhiều exceptions
public void complexOperation()
throws IOException, SQLException, ClassNotFoundException {
// Method implementation
}
6. Custom Exceptions
Tạo exception class riêng:
// Custom checked exception
public class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
public InvalidAgeException(String message, Throwable cause) {
super(message, cause);
}
}
// Custom unchecked exception
public class InsufficientFundsException extends RuntimeException {
private double amount;
public InsufficientFundsException(double amount) {
super("Không đủ tiền: " + amount);
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
// Sử dụng
public class BankAccount {
private double balance;
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount - balance);
}
balance -= amount;
}
}
// Main
try {
account.withdraw(1000);
} catch (InsufficientFundsException e) {
System.out.println("Thiếu: " + e.getAmount());
}
7. Best Practices
- Specific Exceptions: Bắt exception cụ thể thay vì Exception chung chung
- Don't Swallow: Không catch rồi không làm gì
- Use Try-with-resources: Cho file, connection, stream...
- Log Exceptions: Luôn log exception để debug
- Custom Exceptions: Tạo exception riêng cho business logic
// ❌ BAD - Swallowing exception
try {
riskyOperation();
} catch (Exception e) {
// Không làm gì - rất nguy hiểm!
}
// ✅ GOOD - Proper handling
try {
riskyOperation();
} catch (SpecificException e) {
logger.error("Operation failed", e);
// Handle hoặc rethrow
throw new BusinessException("Cannot process", e);
}
Kết luận
Exception handling là kỹ năng quan trọng trong Java:
- Sử dụng try-catch-finally để xử lý lỗi
- Hiểu sự khác biệt checked vs unchecked
- Tạo custom exceptions cho business logic
- Luôn cleanup resources trong finally hoặc try-with-resources