Bỏ qua để đến nội dung

Autoboxing/Unboxing và NullPointerException

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!

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 int
public 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).

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ề null
int total = baseSalary + bonus; // NullPointerException nếu bonus là null! (bonus bị unbox để cộng)

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 null

2. 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ề null

3. Ư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).

Unbox một wrapper class đang là null (ví dụ Integerint) sẽ ném NullPointerException, 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ộn Integer với int
  • Dùng getOrDefault(), kiểm tra null tường minh, hoặc ưu tiên kiểu nguyên thủy khi có thể