1. Xử lý ngoại lệ (Exception Handling)
Trong lập trình Java, cơ chế xử lý ngoại lệ đóng vai trò quan trọng trong việc duy trì sự ổn định của ứng dụng, ngăn chặn việc chương trình bị dừng đột ngột khi gặp lỗi. Cấu trúc thường dùng bao gồm khối try, catch và finally.
Cấu trúc Try-Catch-Finally
public void divideNumbers() {
try {
int numerator = 100;
int denominator = 0;
int result = numerator / denominator;
System.out.println("Kết quả: " + result);
} catch (ArithmeticException ex) {
System.err.println("Phát hiện lỗi chia cho 0: " + ex.getMessage());
} finally {
System.out.println("Khối lệnh finally luôn được thực thi để dọn dẹp tài nguyên.");
}
}
Nguyên tắc khớp ngoại lệ:
- Khối
catchsẽ bắt được ngoại lệ của loại được khai báo cũng như mọi lớp con của nó. - Các khối
catchphải được sắp xếp từ cụ thể đến chung. Lớp ngoại lệ cha (nhưException) phải đặt sau các lớp con, nếu không trình biên dịch sẽ báo lỗi. - Nếu các lớp ngoại lệ không có quan hệ kế thừa, thứ tự xuất hiện không quan trọng.
- Khối
finallylà tùy chọn nhưng nếu có, nó sẽ luôn chạy bất kể có ngoại lệ hay không.
Ném ngoại lệ (Throwing Exceptions)
Chúng ta có thể chủ động ném ngoại lệ bằng từ khóa throw hoặc khai báo phương thức ném ngoại lệ bằng throws.
public void validateAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Tuổi không được là số âm");
}
System.out.println("Tuổi hợp lệ: " + age);
}
// Sử dụng throws để chuyển trách nhiệm xử lý cho phương thức gọi
public void readFile(String path) throws IOException {
// Logic đọc file có thể ném IOException
}
Tạo lớp ngoại lệ tùy chỉnh
Để xử lý các lỗi nghiệp vụ cụ thể, chúng ta có thể định nghĩa lớp ngoại lệ mới kế thừa từ Exception hoặc RuntimeException.
public class BusinessRuleException extends Exception {
private String errorCode;
public BusinessRuleException(String code, String message) {
super(message);
this.errorCode = code;
}
@Override
public String toString() {
return "Lỗi " + errorCode + ": " + getMessage();
}
}
2. Các lớp dữ liệu phổ biến (Common Classes)
Lớp bao bọc (Wrapper Classes)
Java là ngôn ngữ hướng đối tượng, nhưng các kiểu dữ liệu nguyên thủy (int, double, v.v.) không phải là đối tượng. Các lớp bao bọc (như Integer, Double) giúp chuyển đổi chúng thành đối tượng để sử dụng trong các cấu trúc dữ liệu như Collection.
// Chuyển đổi từ nguyên thủy sang đối tượng (Boxing)
int value = 50;
Integer wrapperValue = Integer.valueOf(value);
// Chuyển đổi từ đối tượng về nguyên thủy (Unboxing)
int primitiveValue = wrapperValue.intValue();
// Tự động đóng gói và mở gói (Autoboxing/Unboxing)
Integer autoBox = 100; // Tự động chuyển thành Integer
int autoUnbox = autoBox; // Tự động chuyển thành int
Lớp String
String đại diện cho chuỗi ký tự và có tính bất biến (immutable). Một khi đối tượng String được tạo, nội dung của nó không thể thay đổi. Mọi thao tác chỉnh sửa đều tạo ra đối tượng mới.
String greeting = "Xin chào";
String target = new String("Java");
// Nối chuỗi (tạo đối tượng mới)
String message = greeting + " " + target;
// So sánh nội dung chuỗi
boolean isMatch = greeting.equals("Xin chào");
Lớp BigDecimal
Trong các tính toán tài chính đòi hỏi độ chính xác cao, float và double có thể gây ra lỗi làm tròn. BigDecimal là giải pháp thay thế an toàn hơn cho số thập phân.
import java.math.BigDecimal;
BigDecimal price = new BigDecimal("19.99");
BigDecimal tax = new BigDecimal("0.05");
// Các phép tính toán học
BigDecimal totalTax = price.multiply(tax);
BigDecimal finalPrice = price.add(totalTax);
3. Bộ sưu tập và Generics (Collections and Generics)
Giao diện List
List là một tập hợp có thứ tự, cho phép chứa các phần tử trùng lặp. ArrayList là implementation phổ biến nhất nhờ hiệu suất truy cập ngẫu nhiên tốt.
import java.util.ArrayList;
import java.util.List;
public void listExample() {
List<String> inventory = new ArrayList<>();
inventory.add("Laptop");
inventory.add("Mouse");
inventory.add("Monitor");
// Duyệt qua danh sách
for (String item : inventory) {
System.out.println("Sản phẩm: " + item);
}
}
Giao diện Set
Set là tập hợp không cho phép chứa các phần tử trùng lặp. Nó thường được sử dụng để lọc bỏ các dữ liệu thừa. HashSet sử dụng bảng băm để lưu trữ.
import java.util.HashSet;
import java.util.Set;
public void setExample() {
Set<String> uniqueIds = new HashSet<>();
uniqueIds.add("ID001");
uniqueIds.add("ID002");
uniqueIds.add("ID001"); // Phần tử này sẽ bị bỏ qua vì đã tồn tại
System.out.println("Số lượng ID duy nhất: " + uniqueIds.size());
}
Giao diện Map
Map lưu trữ dữ liệu dưới dạng cặp khóa-giá trị (Key-Value). Mỗi khóa là duy nhất và dùng để truy xuất giá trị tương ứng. HashMap là lớp triển khai thường gặp nhất.
import java.util.HashMap;
import java.util.Map;
class Product {
private String code;
private String label;
public Product(String code, String label) {
this.code = code;
this.label = label;
}
public String getLabel() { return label; }
}
public void mapExample() {
Map<String, Product> productCatalog = new HashMap<>();
Product p1 = new Product("P101", "Điện thoại");
Product p2 = new Product("P102", "Tai nghe");
productCatalog.put(p1.code, p1);
productCatalog.put(p2.code, p2);
// Truy xuất sản phẩm bằng mã
Product found = productCatalog.get("P101");
if (found != null) {
System.out.println("Tìm thấy: " + found.getLabel());
}
}