NullPointerException
Vấn đề
Phần tiêu đề “Vấn đề”NullPointerException (thường viết tắt NPE) là lỗi runtime phổ biến nhất trong Java - xảy ra khi bạn cố gắng dùng một tham chiếu null như thể nó trỏ đến một đối tượng thật sự:
String name = null;System.out.println(name.length()); // NullPointerException! name không trỏ đến đối tượng nàopublic class Person { String name;}
Person person = new Person(); // person.name mặc định là null (chưa gán)System.out.println(person.name.toUpperCase()); // NullPointerException!Vì sao nguy hiểm?
Phần tiêu đề “Vì sao nguy hiểm?”nulllà giá trị mặc định hợp lệ cho mọi kiểu tham chiếu (object) - trình biên dịch không ngăn bạn gánnullhay truyềnnullvào nơi cần đối tượng thật- Lỗi chỉ xuất hiện lúc chạy chương trình, thường ở một dòng xa nơi
nullthực sự được tạo ra, gây khó truy vết - Rất dễ xảy ra với kết quả trả về từ
Map.get()(trảnullnếu không tìm thấy khóa), hoặc dữ liệu chưa khởi tạo
import java.util.HashMap;import java.util.Map;
Map<String, Integer> ages = new HashMap<>();int age = ages.get("An"); // "An" không có trong map -> get() trả về null// NullPointerException khi unbox null Integer thành int!Giải pháp
Phần tiêu đề “Giải pháp”1. Kiểm tra null trước khi dùng:
String name = getName(); // giả sử có thể trả về nullif (name != null) { System.out.println(name.length());}2. Dùng Objects.requireNonNull() để báo lỗi rõ ràng, sớm hơn:
import java.util.Objects;
public Person(String name) { this.name = Objects.requireNonNull(name, "name không được null");}3. Dùng Optional (Java 8+) để biểu thị rõ ràng “có thể không có giá trị”:
import java.util.Optional;
Optional<String> maybeName = Optional.ofNullable(getName());String result = maybeName.orElse("Không rõ tên"); // giá trị mặc định nếu là null4. Dùng getOrDefault() thay vì get() với Map:
int age = ages.getOrDefault("An", 0); // trả về 0 nếu "An" không tồn tại, thay vì nullTóm tắt
Phần tiêu đề “Tóm tắt”NullPointerException: xảy ra khi gọi phương thức/truy cập field trên một tham chiếu
null.
- Luôn kiểm tra
nulltrước khi dùng dữ liệu có thể chưa được khởi tạo- Cẩn thận với kết quả từ
Map.get()và autoboxing (Integernull không unbox được thànhint)- Cân nhắc dùng
OptionalhoặcObjects.requireNonNull()để xử lý rõ ràng, sớm hơn