Java Collections: Những công cụ ẩn mà bạn đang bỏ lỡ
Hầu hết các lập trình viên đều sử dụng Java collections theo cùng một cách mỗi ngày. Họ sử dụng ArrayLists và HashSets. Nhưng bạn có thể đang bỏ lỡ những công cụ giúp mã nguồn của mình nhanh hơn và an toàn hơn.
Dưới đây là ba công cụ cụ thể để cải thiện mã nguồn của bạn.
- Arrays.asList không phải là một List thực thụ
Khi bạn sử dụng Arrays.asList(array), bạn sẽ nhận được một danh sách có kích thước cố định. Nó liên kết trực tiếp với mảng ban đầu của bạn.
- Nếu bạn thay đổi mảng, danh sách cũng thay đổi.
- Nếu bạn cố gắng thêm hoặc xóa các phần tử, mã của bạn sẽ bị lỗi (crash).
Để khắc phục điều này, hãy bao bọc nó trong một ArrayList mới:
List<String> list = new ArrayList<>(Arrays.asList(array));
Điều này tạo ra một danh sách thực sự, độc lập mà bạn có thể chỉnh sửa.
- Sử dụng EnumSet để tối ưu hiệu suất
Bạn có đang lưu trữ các enum trong một HashSet không? Điều đó tạo ra sự tiêu tốn tài nguyên (overhead) không cần thiết. HashSet sử dụng bảng băm (hash tables) và các object header.
Thay vào đó, hãy sử dụng EnumSet. Nó sử dụng một bit vector ở bên trong. Nó cực kỳ nhanh và hầu như không tốn bộ nhớ. Nó hoàn hảo cho các hệ thống dựa trên flag (cờ) như sức mạnh nhân vật hoặc các thiết lập (settings).
- Nó an toàn về kiểu (type-safe).
- Nó nhanh hơn nhiều so với
HashSet. - Nó xử lý các phép toán bitwise cho bạn.
- Sử dụng ConcurrentHashMap.computeIfAbsent cho các bộ nhớ đệm (caches)
Nếu bạn xây dựng một cache, bạn thường phải viết mã phức tạp để ngăn nhiều luồng (threads) cùng tính toán một giá trị giống nhau. Điều này được gọi là double-checked locking. Nó rất khó đọc và dễ gây lỗi.
Thay vào đó, chỉ cần một dòng:
cache.computeIfAbsent(key, this::expensiveCalculation);
Phương thức này có tính nguyên tử (atomic). Nó đảm bảo việc tính toán chỉ chạy một lần duy nhất, ngay cả khi có nhiều luồng cùng yêu cầu một key tại cùng một thời điểm. Nó giúp giảm thiểu lỗi và làm cho ý định của bạn trở nên rõ ràng.
Tại sao những công cụ này lại quan trọng:
- Hiệu suất có thể dự đoán được: Bạn tránh được các chi phí bộ nhớ ẩn.
- Ít lỗi hơn: Bạn không còn phải đối mặt với các tình trạng tranh chấp (race conditions) trong mã đa luồng.
- Mã nguồn rõ ràng hơn: Các lập trình viên khác có thể hiểu ngay thiết kế của bạn.
Đừng cố chống lại framework. Hãy bắt đầu sử dụng nó để viết mã tinh gọn và an toàn hơn.