null và Optional
Bạn tìm khách hàng theo số điện thoại, nhưng chưa có khách nào dùng số đó nên
kết quả là không có ai. Java dùng null để diễn tả "không có gì", và null
cũng là nguồn gây lỗi phổ biến nhất khi chương trình chạy.
Khái niệm
🕳️ null: giá trị cho biết biến không trỏ tới object nào.
❓ Optional: class bọc một giá trị có thể có hoặc không, như Optional<Customer>, cho nơi gọi biết kết quả có thể rỗng.
Biến kiểu tham chiếu nào cũng nhận được null. Kiểu nguyên thuỷ như int
thì không, muốn "chưa biết" phải dùng class bọc Integer.
Ví dụ
// Main.java
void main() {
Customer found = findByPhone("0900000000");
if (found != null) {
System.out.println(found.getName());
} else {
System.out.println("Không tìm thấy");
}
}
Customer findByPhone(String phone) {
return null; // giả sử không có ai
}
// Customer.java
class Customer {
private String name = "";
public String getName() { return name; }
}- Kiểu
Customerkhông cho người đọc biết kết quả có thể lànull. Phải đọc code củafindByPhonemới biết. - Luôn kiểm tra
!= nulltrước khi dùng một biến có thể lànull. - Compiler không cảnh báo khi bạn dùng biến
nullmà chưa kiểm tra. Lỗi chỉ lộ ra lúc chạy.
Optional
Optional ghi rõ "có thể không có" ngay trong kiểu, và cho sẵn giá trị thay
thế:
// Main.java
void main() {
Optional<String> note = Optional.empty();
Optional<Integer> discount = Optional.empty();
int length = note.orElse("").length();
int percent = discount.orElse(0);
System.out.println(length); // 0
System.out.println(percent); // 0
}Optional.empty(): không có giá trị.Optional.of(x): có giá trịx.Optional.ofNullable(x): rỗng nếuxlànull, có giá trị nếu không.o.orElse(b): nếuorỗng thì lấyb.- Method tìm kiếm nên trả về
Optional<Customer>thay chonull, để nơi gọi thấy ngay phải xử lý trường hợp không tìm thấy.
Thử ngay
Dán vào Main.java rồi chạy java Main.java:
// Main.java
void main() {
String coupon = null;
System.out.println(Optional.ofNullable(coupon)
.orElse("Không có mã"));
coupon = "sale10";
System.out.println(Optional.ofNullable(coupon)
.orElse("Không có mã"));
}Đoán trước khi chạy: lần in đầu tiên có bị lỗi vì coupon đang là
null không?
Xem kết quả
Không có mã
sale10Không lỗi. ofNullable thấy coupon là null nên tạo Optional rỗng, rồi
orElse thay bằng "Không có mã".
Lỗi hay gặp
Dùng biến null mà không kiểm tra. Chương trình dừng với
NullPointerException.
// SAI — lỗi khi chạy: note đang là null
String note = null;
System.out.println(note.length());// ĐÚNG
String note = null;
System.out.println(
Optional.ofNullable(note).orElse("").length());Gán null cho kiểu nguyên thuỷ. int luôn phải có một con số.
// SAI — lỗi compile: int không nhận null
int stock = null;// ĐÚNG — Integer cho phép "chưa biết"
Integer stock = null;Tóm tắt
nullnghĩa là không trỏ tới object nào.- Kiểu tham chiếu nhận được
null, kiểu nguyên thuỷ thì không (dùngIntegerthayint). - Kiểm tra
!= nulltrước khi dùng, hoặc bọc bằngOptionalrồiorElse. - Gọi method trên
nullgâyNullPointerException.
Tự kiểm tra
0/3 câuOptional<Integer> points = Optional.empty(); int total = points.orElse(10); Giá trị của total là gì?
Chương trình dừng với NullPointerException ở dòng customer.getName().toUpperCase(). Nguyên nhân nhiều khả năng nhất là gì?
Khai báo nào hợp lệ?