NullPointerException là một lỗi thường gặp đối với người lập trình Java. Thường gặp đến nỗi, ngay cả những người có kinh nghiệm code nhiều năm cũng hay bị lỗi này. Mình thường troll một đồng nghiệp trong công ty rằng: tao thấy mầy code rất giỏi, không bao giờ có lỗi (mặt nó hí hửng), nếu mà có lỗi thì chỉ có NPE (viết tắt của NullPointerException) thôi (xịu liền).
Vì thế trong bài viết này mình xin chia sẻ với các bạn một số cách để tránh lỗi này, tất nhiên các bạn phải thực tập thường xuyên chứ ai cũng hay quên lắm, mình cũng vậy :D.
Tại sao chúng ta hay bị lỗi này? Đó là bởi vì chúng ta khi sử dụng đối tượng không nhìn hết được những đối tượng mà chúng ta đang sử dụng đã được khởi tạo hay chưa? Nếu chúng chưa được khởi tạo mà chúng ta lại cố gắng sử dụng chúng, lỗi này sẽ xảy ra!
Sau đây, mình sẽ liệt kê ra một số trường hợp có thể xảy ra lỗi này:
So sánh 2 chuỗi
Các bạn hãy xem đoạn code phía dưới:
1 2 3 |
public boolean checkName(String name) { return name.equalsIgnoreCase("David"); } |
Sẽ như thế nào nếu biến name trong phương thức trên là null, khi chạy chúng ta sẽ bị NullPointerException ngay.
Vậy trong trường hợp này chúng ta nên code như thế nào nhỉ? Dưới đây là một gợi ý cho các bạn:
1 2 3 |
public boolean checkName(String name) { return "David".equalsIgnoreCase(name); } |
Các bạn thấy đó, bởi vì chuỗi “David” là một đối tượng không bao giờ null nên khi chúng ta cố gắng sử dụng nó để so sánh với giá trị của biến name, NullPointerException sẽ không bao giờ xảy ra.
Trả về một giá trị null khi xử lý một Collection rỗng
Xem xét đoạn code sau nhé các bạn
1 2 3 4 |
public List<Product> findByProductId(String productId) { // TODO: implement this method return null; } |
Nếu một ai đó sử dụng phương thức này trong code của họ, và họ cố gắng đọc danh sách này ra, thì họ sẽ bị NullPointerException ngay.
Vì vậy, đối với một Collection rỗng khi trả về, các bạn nên trả lại một Collection rỗng luôn, vì khi đó, dù người khác có dùng code của bạn, danh sách rỗng cũng không bị vấn đề gì.
Trong Java, chúng ta có một lớp Collections giúp chúng ta có thể trả về một Collection rỗng mà không tốn nhiều bộ nhớ. Hãy trả về Collections.EMPTY_LIST cho đối tượng List, Collections.EMPTY_SET cho đối tượng Set và Collections.EMPTY_MAP cho đối tượng Map các bạn nhé!
Ví dụ phương thức trên có thể viết lại thành:
1 2 3 4 |
public List<Product> findByProductId(String productId) { // TODO: implement this method return Collections.EMPTY_LIST; } |
Truy cập một đối tượng có thể bị null
Trong trường hợp chúng ta không chắc chắn khi nào đối tượng của chúng ta bị null, chúng ta vẫn muốn sử dụng đối tượng đó trong trường hợp nó không bị null.
Vẫn có cách để xử lý trong trường hợp này:
- Cách đầu tiên là kiểm tra null hết tất cả các đối tượng có thể bị null, nếu nó không bị null thì code chúng ta sẽ tiếp tục chạy còn ngược lại sẽ dừng. Ví dụ kiểm tra null như sau:
1 2 3 4 5 6 7 8 9 |
public String getName(String id) { return null; } // example String name = getName(1); if (name != null) {} System.out.println(name.toString()); } |
- Cách thứ hai là dùng try … catch của Java để bắt lỗi này:
1 2 3 4 5 6 7 8 9 10 11 |
public String getName(String id) { return null; } // example String name = getName(1); try { System.out.println(name.toString()); } catch (NullPointerException npe) { } |
Từ Java 8 trở đi, chúng ta còn có thêm một lựa chọn khác để tránh lỗi NullPointerException trong Java, đó chính là sử dụng đối tượng Optional. Các bạn có thể tham khảo bài viết về đối tượng Optional ở đây.