Autoboxing/Unboxing và NullPointerException
Vấn đề
Phần tiêu đề “Vấn đề”Java tự động chuyển đổi qua lại giữa kiểu nguyên thủy (int) và wrapper class (Integer) - gọi là autoboxing (int → Integer) và unboxing (Integer → int). Quá trình unboxing một Integer đang là null sẽ ném NullPointerException, dù code trông như đang làm việc với int bình thường:
Integer value = null;int number = value; // unboxing null -> NullPointerException!Vì sao nguy hiểm?
Phần tiêu đề “Vì sao nguy hiểm?”Lỗi này dễ ẩn náu vì code trông hoàn toàn bình thường, không có dấu hiệu rõ ràng nào cho thấy đang thao tác với một đối tượng có thể null:
import java.util.HashMap;import java.util.Map;
Map<String, Integer> scores = new HashMap<>();scores.put("An", 90);
int score = scores.get("Bình"); // "Bình" không có trong map -> get() trả về null// NullPointerException! Đang unbox null Integer thành intpublic class Student { Integer age; // wrapper class - mặc định null nếu chưa gán, KHÁC với int (mặc định 0)}
Student student = new Student();int age = student.age; // student.age là null -> NullPointerException khi unbox!So sánh với kiểu nguyên thủy int age; - trường hợp này không thể xảy ra vì int không bao giờ là null (mặc định là 0).
Cẩn thận cả trong biểu thức số học
Phần tiêu đề “Cẩn thận cả trong biểu thức số học”Toán tử số học trên Integer cũng tự động unbox - dễ gây NPE ở nơi không ngờ tới:
Integer bonus = getBonusOrNull(); // giả sử có thể trả về nullint total = baseSalary + bonus; // NullPointerException nếu bonus là null! (bonus bị unbox để cộng)Giải pháp
Phần tiêu đề “Giải pháp”1. Kiểm tra null trước khi unbox:
Integer value = scores.get("Bình");int score = (value != null) ? value : 0; // dùng giá trị mặc định nếu null2. Dùng getOrDefault() với Map thay vì get():
int score = scores.getOrDefault("Bình", 0); // an toàn - không bao giờ trả về null3. Ưu tiên kiểu nguyên thủy (int) thay vì wrapper class (Integer) cho field khi có thể, chỉ dùng wrapper class khi thực sự cần biểu diễn “không có giá trị” (như trong generic collection, nơi bắt buộc phải dùng wrapper).
Tóm tắt
Phần tiêu đề “Tóm tắt”Unbox một wrapper class đang là
null(ví dụInteger→int) sẽ némNullPointerException, dù code trông như thao tác bình thường với số.
- Cẩn thận với kết quả từ
Map.get(), field kiểu wrapper class chưa khởi tạo, và biểu thức số học trộnIntegervớiint- Dùng
getOrDefault(), kiểm tranulltường minh, hoặc ưu tiên kiểu nguyên thủy khi có thể