Chuyển tới nội dung chính

Ngoại Lệ Tùy Chỉnh trong Java 🎨

🎯 Mục tiêu: Học cách tạo và sử dụng ngoại lệ tùy chỉnh để xử lý các tình huống đặc biệt trong ứng dụng Java của bạn.

Giới thiệu 📝

Ngoại lệ tùy chỉnh (Custom Exceptions) cho phép bạn tạo các loại ngoại lệ riêng để xử lý các tình huống đặc biệt trong ứng dụng của bạn. Chúng giúp code dễ đọc và dễ bảo trì hơn bằng cách phân biệt rõ ràng các loại lỗi khác nhau.

💡 Fun Fact: Ngoại lệ tùy chỉnh giúp bạn tạo ra một hệ thống xử lý lỗi riêng cho ứng dụng, giúp code dễ hiểu và dễ debug hơn.

1. Ngoại Lệ Tùy Chỉnh Cơ Bản ⚡

Ngoại Lệ Checked

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

Ngoại Lệ Unchecked

public class BusinessRuleException extends RuntimeException {
public BusinessRuleException(String message) {
super(message);
}
}

2. Ngoại Lệ với Thông Tin Bổ Sung 🔍

Ngoại Lệ với Mã Lỗi

public class ApiException extends Exception {
private String errorCode;
private int statusCode;

public ApiException(String message, String errorCode, int statusCode) {
super(message);
this.errorCode = errorCode;
this.statusCode = statusCode;
}

public String getErrorCode() {
return errorCode;
}

public int getStatusCode() {
return statusCode;
}
}

Ngoại Lệ với Dữ Liệu Bổ Sung

public class DataValidationException extends Exception {
private String fieldName;
private Object invalidValue;

public DataValidationException(String message, String fieldName, Object invalidValue) {
super(message);
this.fieldName = fieldName;
this.invalidValue = invalidValue;
}

public String getFieldName() {
return fieldName;
}

public Object getInvalidValue() {
return invalidValue;
}
}

3. Ngoại Lệ với Xử Lý Đặc Biệt 🛠️

Ngoại Lệ với Logging

public class LoggedException extends Exception {
private static final Logger logger = Logger.getLogger(LoggedException.class.getName());

public LoggedException(String message) {
super(message);
logger.error("Ngoại lệ xảy ra: " + message);
}

public LoggedException(String message, Throwable cause) {
super(message, cause);
logger.error("Ngoại lệ xảy ra: " + message, cause);
}
}

Ngoại Lệ với Khôi Phục

public class RecoverableException extends Exception {
private final String recoveryAction;

public RecoverableException(String message, String recoveryAction) {
super(message);
this.recoveryAction = recoveryAction;
}

public String getRecoveryAction() {
return recoveryAction;
}

public void attemptRecovery() {
// Thực hiện hành động khôi phục
System.out.println("Đang thực hiện khôi phục: " + recoveryAction);
}
}

4. Ví Dụ Thực Tế 🚀

Xử Lý Đơn Hàng

public class OrderException extends Exception {
private String orderId;
private String status;

public OrderException(String message, String orderId, String status) {
super(message);
this.orderId = orderId;
this.status = status;
}

public String getOrderId() {
return orderId;
}

public String getStatus() {
return status;
}
}

public class OrderProcessor {
public void processOrder(String orderId) throws OrderException {
// Kiểm tra trạng thái đơn hàng
if (!isValidStatus(orderId)) {
throw new OrderException(
"Đơn hàng không thể xử lý",
orderId,
getOrderStatus(orderId)
);
}
// Xử lý đơn hàng
}
}

Xử Lý Thanh Toán

public class PaymentException extends Exception {
private String transactionId;
private double amount;
private String currency;

public PaymentException(String message, String transactionId,
double amount, String currency) {
super(message);
this.transactionId = transactionId;
this.amount = amount;
this.currency = currency;
}

public String getTransactionId() {
return transactionId;
}

public double getAmount() {
return amount;
}

public String getCurrency() {
return currency;
}
}

public class PaymentService {
public void processPayment(String transactionId, double amount)
throws PaymentException {
// Kiểm tra số tiền
if (amount <= 0) {
throw new PaymentException(
"Số tiền không hợp lệ",
transactionId,
amount,
"VND"
);
}
// Xử lý thanh toán
}
}

Xử Lý API Request

public class ApiRequestException extends Exception {
private String endpoint;
private String method;
private Map<String, String> headers;

public ApiRequestException(String message, String endpoint,
String method, Map<String, String> headers) {
super(message);
this.endpoint = endpoint;
this.method = method;
this.headers = headers;
}

public String getEndpoint() {
return endpoint;
}

public String getMethod() {
return method;
}

public Map<String, String> getHeaders() {
return headers;
}
}

public class ApiService {
public void makeRequest(String endpoint, String method,
Map<String, String> headers) throws ApiRequestException {
// Kiểm tra endpoint
if (!endpoint.startsWith("/api/")) {
throw new ApiRequestException(
"Endpoint không hợp lệ",
endpoint,
method,
headers
);
}
// Xử lý request
}
}

5. Best Practices ✅

  1. Đặt Tên Rõ Ràng

    // Không nên
    public class MyException extends Exception { }

    // Nên
    public class InvalidUserInputException extends Exception { }
  2. Kế Thừa Từ Exception Phù Hợp

    // Không nên
    public class ValidationError extends Exception { } // Checked exception

    // Nên
    public class ValidationError extends RuntimeException { } // Unchecked exception
  3. Thêm Thông Tin Hữu Ích

    // Không nên
    public class ErrorException extends Exception {
    public ErrorException(String message) {
    super(message);
    }
    }

    // Nên
    public class ValidationError extends Exception {
    private String fieldName;
    private Object invalidValue;

    public ValidationError(String message, String fieldName, Object invalidValue) {
    super(message);
    this.fieldName = fieldName;
    this.invalidValue = invalidValue;
    }
    }

6. Lỗi Thường Gặp ⚠️

  1. Quên Gọi Super Constructor

    // Lỗi
    public class CustomException extends Exception {
    public CustomException(String message) {
    // Quên gọi super(message)
    }
    }

    // Đúng
    public class CustomException extends Exception {
    public CustomException(String message) {
    super(message);
    }
    }
  2. Sử Dụng Exception Chung

    // Không nên
    throw new Exception("Lỗi chung");

    // Nên
    throw new CustomException("Lỗi cụ thể");
  3. Quên Thêm Thông Tin Chi Tiết

    // Không nên
    public class ValidationException extends Exception {
    public ValidationException(String message) {
    super(message);
    }
    }

    // Nên
    public class ValidationException extends Exception {
    private String fieldName;
    private Object invalidValue;

    public ValidationException(String message, String fieldName, Object invalidValue) {
    super(message);
    this.fieldName = fieldName;
    this.invalidValue = invalidValue;
    }
    }

7. Ví Dụ Thực Tế Nâng Cao 🎯

Xử Lý Đa Luồng

public class ThreadExecutionException extends Exception {
private String threadName;
private long executionTime;
private String failureReason;

public ThreadExecutionException(String message, String threadName,
long executionTime, String failureReason) {
super(message);
this.threadName = threadName;
this.executionTime = executionTime;
this.failureReason = failureReason;
}

public String getThreadName() {
return threadName;
}

public long getExecutionTime() {
return executionTime;
}

public String getFailureReason() {
return failureReason;
}
}

public class ThreadManager {
public void executeTask(Runnable task, String threadName)
throws ThreadExecutionException {
long startTime = System.currentTimeMillis();
try {
Thread thread = new Thread(task, threadName);
thread.start();
thread.join();
} catch (InterruptedException e) {
throw new ThreadExecutionException(
"Task bị gián đoạn",
threadName,
System.currentTimeMillis() - startTime,
"InterruptedException"
);
}
}
}

Xử Lý Giao Dịch

public class TransactionException extends Exception {
private String transactionId;
private TransactionStatus status;
private List<String> affectedAccounts;

public TransactionException(String message, String transactionId,
TransactionStatus status, List<String> affectedAccounts) {
super(message);
this.transactionId = transactionId;
this.status = status;
this.affectedAccounts = affectedAccounts;
}

public String getTransactionId() {
return transactionId;
}

public TransactionStatus getStatus() {
return status;
}

public List<String> getAffectedAccounts() {
return affectedAccounts;
}
}

public class TransactionManager {
public void processTransaction(String transactionId, double amount,
List<String> accounts) throws TransactionException {
try {
// Thực hiện giao dịch
updateBalances(accounts, amount);
} catch (Exception e) {
throw new TransactionException(
"Lỗi xử lý giao dịch",
transactionId,
TransactionStatus.FAILED,
accounts
);
}
}
}

Xử Lý Cache

public class CacheException extends Exception {
private String cacheKey;
private CacheOperation operation;
private Map<String, Object> context;

public CacheException(String message, String cacheKey,
CacheOperation operation, Map<String, Object> context) {
super(message);
this.cacheKey = cacheKey;
this.operation = operation;
this.context = context;
}

public String getCacheKey() {
return cacheKey;
}

public CacheOperation getOperation() {
return operation;
}

public Map<String, Object> getContext() {
return context;
}
}

public class CacheManager {
public void updateCache(String key, Object value) throws CacheException {
Map<String, Object> context = new HashMap<>();
context.put("value", value);

try {
cache.put(key, value);
} catch (Exception e) {
throw new CacheException(
"Lỗi cập nhật cache",
key,
CacheOperation.UPDATE,
context
);
}
}
}

💡 Lời khuyên: Hãy thực hành với các ví dụ thực tế để hiểu rõ hơn về cách tạo và sử dụng ngoại lệ tùy chỉnh trong các tình huống khác nhau.

Tiếp Theo 🎯

Trong các bài học tiếp theo, chúng ta sẽ:

  • Tìm hiểu về exception chaining
  • Học cách tạo exception hierarchy
  • Thực hành với các ví dụ thực tế
  • Tìm hiểu về exception handling patterns