0

[Java Backend Zero to Hello] BÀI 1.9: XỬ LÝ NGOẠI LỆ (EXCEPTION HANDLING)

Java Backend Zero to Hello

📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 1: Java Core Cơ Bản | Bài 11/86


BÀI 1.9: XỬ LÝ NGOẠI LỆ (EXCEPTION HANDLING)

Mục tiêu

  • Hiểu cơ chế xử lý lỗi trong Java
  • Phân biệt Checked và Unchecked Exception
  • Sử dụng try-catch-finally, throw, throws
  • Tạo Custom Exception

1. EXCEPTION LÀ GÌ?

Exception là sự kiện bất thường xảy ra trong quá trình thực thi, làm gián đoạn luồng chương trình.

Ví dụ

  • Chia cho 0
  • Truy cập mảng ngoài phạm vi
  • Mở file không tồn tại
  • Nhập sai định dạng dữ liệu

2. HỆ THỐNG PHÂN CẤP EXCEPTION

Throwable
├── Error (Không xử lý được)
│   ├── OutOfMemoryError
│   ├── StackOverflowError
│   └── ...
└── Exception (Có thể xử lý)
    ├── IOException (Checked)
    ├── SQLException (Checked)
    ├── ClassNotFoundException (Checked)
    └── RuntimeException (Unchecked)
        ├── NullPointerException
        ├── ArrayIndexOutOfBoundsException
        ├── ArithmeticException
        ├── NumberFormatException
        └── IllegalArgumentException

Checked vs Unchecked

Loại Khi nào Bắt buộc xử lý?
Checked Lỗi dự đoán được (I/O, network) ✅ Bắt buộc try-catch hoặc throws
Unchecked Lỗi logic (RuntimeException) ❌ Không bắt buộc
Error Lỗi hệ thống (JVM) ❌ Không nên xử lý

3. CÚ PHÁP TRY-CATCH-FINALLY

3.1 Cơ bản

try {
    // Code có thể gây exception
    int result = 10 / 0;
} catch (ArithmeticException e) {
    // Xử lý khi exception xảy ra
    System.out.println("Lỗi chia cho 0: " + e.getMessage());
} finally {
    // Luôn thực thi (dù có exception hay không)
    System.out.println("Kết thúc xử lý");
}

3.2 Nhiều catch block

try {
    String s = null;
    System.out.println(s.length());
} catch (NullPointerException e) {
    System.out.println("Null pointer");
} catch (ArithmeticException e) {
    System.out.println("Lỗi toán học");
} catch (Exception e) {
    // Catch tổng quát - đặt cuối cùng
    System.out.println("Lỗi khác: " + e.getMessage());
}

3.3 Multi-catch (Java 7+)

try {
    // ...
} catch (IOException | SQLException e) {
    System.out.println("Lỗi I/O hoặc SQL: " + e.getMessage());
}

3.4 Try-with-resources (Java 7+)

Tự động đóng resource (AutoCloseable).

try (Scanner sc = new Scanner(new File("data.txt"));
     BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    // Sử dụng sc, br
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
// sc và br tự động được đóng

4. THROW VÀ THROWS

4.1 Throw - Ném exception

public void setAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("Tuổi không được âm");
    }
    this.age = age;
}

4.2 Throws - Khai báo exception

public void readFile(String path) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    // ...
}

4.3 So sánh

throw throws
Ném một exception cụ thể Khai báo method có thể ném exception
Dùng trong thân method Dùng trong signature method
Theo sau là một object Theo sau là một hoặc nhiều class

5. CÁC EXCEPTION PHỔ BIẾN

5.1 NullPointerException

String s = null;
System.out.println(s.length());  // ❌ NullPointerException

// Cách tránh
if (s != null) {
    System.out.println(s.length());
}
// Hoặc dùng Optional (Java 8+)
Optional.ofNullable(s).ifPresent(str -> System.out.println(str.length()));

5.2 ArrayIndexOutOfBoundsException

int[] arr = {1, 2, 3};
System.out.println(arr[5]);  // ❌

// Cách tránh
if (index >= 0 && index < arr.length) {
    System.out.println(arr[index]);
}

5.3 NumberFormatException

String s = "abc";
int n = Integer.parseInt(s);  // ❌

// Cách tránh
try {
    int n = Integer.parseInt(s);
} catch (NumberFormatException e) {
    System.out.println("Không phải số");
}

5.4 ArithmeticException

int result = 10 / 0;  // ❌

// Cách tránh
if (divisor != 0) {
    int result = dividend / divisor;
}

5.5 ClassCastException

Object obj = "Hello";
Integer n = (Integer) obj;  // ❌

// Cách tránh
if (obj instanceof Integer) {
    Integer n = (Integer) obj;
}

6. CUSTOM EXCEPTION

6.1 Unchecked Custom Exception

public class InsufficientFundsException extends RuntimeException {
    private double amount;

    public InsufficientFundsException(String message, double amount) {
        super(message);
        this.amount = amount;
    }

    public double getAmount() {
        return amount;
    }
}

// Sử dụng
public class BankAccount {
    private double balance;

    public void withdraw(double amount) {
        if (amount > balance) {
            throw new InsufficientFundsException(
                "Số dư không đủ. Thiếu: " + (amount - balance),
                amount - balance
            );
        }
        balance -= amount;
    }
}

6.2 Checked Custom Exception

public class InvalidUserException extends Exception {
    public InvalidUserException(String message) {
        super(message);
    }

    public InvalidUserException(String message, Throwable cause) {
        super(message, cause);
    }
}

// Sử dụng - bắt buộc try-catch hoặc throws
public void register(User user) throws InvalidUserException {
    if (user.getAge() < 18) {
        throw new InvalidUserException("Người dùng chưa đủ 18 tuổi");
    }
    // ...
}

7. CÁC METHOD CỦA EXCEPTION

try {
    // ...
} catch (Exception e) {
    System.out.println(e.getMessage());      // Thông báo lỗi
    System.out.println(e.toString());        // Tên + message
    e.printStackTrace();                     // In stack trace
    System.out.println(e.getClass().getName());  // Tên class
}

Stack trace

java.lang.ArithmeticException: / by zero
    at com.example.Main.divide(Main.java:10)
    at com.example.Main.main(Main.java:5)

8. BEST PRACTICES

8.1 Catch exception cụ thể

// ❌ Xấu
try {
    // ...
} catch (Exception e) {
    e.printStackTrace();
}

// ✅ Tốt
try {
    // ...
} catch (FileNotFoundException e) {
    // Xử lý cụ thể
}

8.2 Không nuốt exception

// ❌ Xấu
try {
    // ...
} catch (Exception e) {
    // Không làm gì
}

// ✅ Tốt
try {
    // ...
} catch (Exception e) {
    log.error("Lỗi xảy ra", e);
    throw new RuntimeException(e);
}

8.3 Dùng try-with-resources

// ❌ Dài dòng
Connection conn = null;
try {
    conn = dataSource.getConnection();
    // ...
} finally {
    if (conn != null) conn.close();
}

// ✅ Gọn
try (Connection conn = dataSource.getConnection()) {
    // ...
}

8.4 Không dùng exception cho luồng điều khiển

// ❌ Xấu
try {
    while (true) {
        int x = iterator.next();  // Ném exception khi hết
    }
} catch (NoSuchElementException e) {
    // Dùng exception để thoát vòng lặp
}

// ✅ Tốt
while (iterator.hasNext()) {
    int x = iterator.next();
}

8.5 Document exception với Javadoc

/**
 * Rút tiền từ tài khoản.
 *
 * @param amount Số tiền cần rút
 * @throws InsufficientFundsException Nếu số dư không đủ
 */
public void withdraw(double amount) throws InsufficientFundsException {
    // ...
}

9. BÀI TẬP THỰC HÀNH

Bài 1: Máy tính an toàn

public class SafeCalculator {
    public static double divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("Không thể chia cho 0");
        }
        return (double) a / b;
    }
}

Bài 2: Validate User

Tạo custom exception InvalidEmailException, InvalidPasswordException và validate user.

Bài 3: Đọc file an toàn

public String readFile(String path) {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.lines().collect(Collectors.joining("\n"));
    } catch (IOException e) {
        return "Không đọc được file: " + e.getMessage();
    }
}

Bài 4: Hệ thống đặt vé

  • SeatUnavailableException - Ghế đã được đặt
  • InvalidPaymentException - Thanh toán không hợp lệ

10. TÓM TẮT

Khái niệm Điểm chính
Checked Exception Bắt buộc xử lý (compile time)
Unchecked Exception RuntimeException, không bắt buộc
try-catch-finally Bắt và xử lý exception
try-with-resources Tự động đóng resource
throw Ném exception
throws Khai báo method có thể ném exception
Custom Exception Kế thừa Exception hoặc RuntimeException

Bài tiếp theo: 1.10 Collections Framework (phần 1)


🧭 Điều Hướng Series

⬅️ Bài trước: BÀI 1.8: ABSTRACT CLASS & INTERFACE

📋 Lộ trình tổng quan: Xem Toàn Bộ Series

➡️ Bài tiếp theo: BÀI 1.10: COLLECTIONS FRAMEWORK (PHẦN 1)


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí