NullPointerException luôn ám ảnh các lập trình viên Java.
Lập trình viên Java từ lúc bắt đầu đã quá quen thuộc với lỗi Null Pointer Exception (NPE). Hầu hết các trường hợp ngoại lệ NPE đều dễ dàng tìm được ra lỗi, nhưng với các ứng dụng lớn mức độ doanh nghiệp có đến hàng trăm class khác nhau, NPE trở thành cơn ác mộng đích thực.

NullPointerException là gì?

NullPointerException (NPE) là lỗi ngoại lệ xảy ra khi lập trình viên tham chiếu tới Object nhưng nó lại không có vị trí nào trên bộ nhớ (null). Gọi một method tham chiếu null hoặc cố gắng truy cập một trường tham chiếu null là một trong những nguyên nhân phổ biến gây ra lỗi Null Pointer Exception.

Theo JavaDoc, NPE được gây ra bởi những nguyên nhân:

  • Ném null như kiểu nó là một giá trị Throwable.

  • Gọi một Instance method của một null object.

  • Truy cập hoặc tùy chỉnh trường giá trị của null object.

  • .Lấy độ dài của Null như một mảng.

  • Truy cập hoặc tùy chỉnh giá trị Null như kiểu một mảng.

Làm cách nào để thực sự phòng tránh được lỗi java.lang.NullPointerException khi chạy chương trình?

Bài viết sẽ điểm qua một vài ví dụ gây ra lỗi NPE và những cách giải quyết:

Chúng ta tạo lỗi NullPointerException theo 3 cách khác nhau:

  1. Gây lỗi NPE nếu bạn cố gắng truy nhập null Object.

  2. Gây lỗi NPE nếu bạn cố đổi null String.

  3. Gây lỗi NPE nếu bạn cố truy nhập null Object trong quá trình khởi tạo Class.

Tham khảo các khóa học lập trình online, onlab, và thực tập lập trình tại TechMaster

Tạo class mẫu như dưới đây: NullPointerExceptionTechmasterVN.java

package techmaster.edu.java;

public class NullPointerExceptionTechmasterVN {
	public static void main(String[] args) {
		try {
			
			// VD1: Lỗi NPE xảy ra nếu bạn cố truy nhập một null Object
			TechmasterNPE1();
		} catch (NullPointerException techmaster1) {
			System.out.println("Exception in TechmasterNPE1()");
			techmaster1.printStackTrace();
		}
 
		try {
			
			// VD2: Lỗi NPE xảy ra khi bạn có đổi một null String
			TechmasterNPE2();
		} catch (NullPointerException techmaster2) {
			System.out.println("\nException in TechmasterNPE2()");
			techmaster2.printStackTrace();
		}
 
		try {
			//VD 3: Lỗi NPE xảy ra khi bạn cố truy nhập
			//null Object trong quá trình khởi tạo class
			
			TechmasterNPETest npe = new TechmasterNPETest();
			npe.getName();
		} catch (NullPointerException npe3) {
			System.out.println("\n Exception in TechmasterNPETest()");
			npe3.printStackTrace();
		}
 
	}
 
	private static void TechmasterNPE1() {
		Object techmasterObj = null;
		techmasterObj.hashCode();
	}
 
	private static void TechmasterNPE2() {
		String techmasterString;

		//Chúng ta gọi một biến techmasterString có kiểu giá trị String
		//Biên chưa trỏ tới giá trị cụ thể, nên Java mặc định giá trị nó là null

		techmasterString = "http://techmaster.vn";

                //Sau dòng lệnh trên, biến được gọi giá trị cụ thể 
                //với giá trị cụ thể trên bộ nhớ
		// nên sẽ không bị lỗi NullPointerException


		System.out.println("\nvalue: " + techmasterString.toString() + ", lenght: " + techmasterString.length());
		System.out.println("No NPE exception");
 
		// Giờ tạo ra lỗi NullPointerException nào
		String techmasterString2 = null;
		System.out.println(techmasterString2.toString());
 
	}	
}
 
class TechmasterNPETest {
	private String techmasterName;
 
	public void setName(String name) {
		this.techmasterName = name;
	}
 
	public void getName() {
		printName(techmasterName);
	}
 
	private void printName(String s) {
		System.out.println(s + " (" + s.length() + ")");
	}
}

Két quả như sau:

Exception in TechmasterNPE1()
java.lang.NullPointerException
	at techmaster.edu.java.NullPointerExceptionTechmasterVN.TechmasterNPE1(NullPointerExceptionTechmasterVN.java:34)
	at techmaster.edu.java.NullPointerExceptionTechmasterVN.main(NullPointerExceptionTechmasterVN.java:7)

value: http://techmaster.vn, lenght: 20
No NPE exception

Exception in TechmasterNPE2()
java.lang.NullPointerException
	at techmaster.edu.java.NullPointerExceptionTechmasterVN.TechmasterNPE2(NullPointerExceptionTechmasterVN.java:51)
	at techmaster.edu.java.NullPointerExceptionTechmasterVN.main(NullPointerExceptionTechmasterVN.java:15)

 Exception in TechmasterNPETest()
java.lang.NullPointerException
	at techmaster.edu.java.TechmasterNPETest.printName(NullPointerExceptionTechmasterVN.java:68)
	at techmaster.edu.java.TechmasterNPETest.getName(NullPointerExceptionTechmasterVN.java:64)
	at techmaster.edu.java.NullPointerExceptionTechmasterVN.main(NullPointerExceptionTechmasterVN.java:24)

Dưới đây là một vài mẹo tránh lỗi NullPointerException:

#1: Sử dụng gợi ý trên IDE tránh lỗi

Gợi ý thông báo trên Eclipse IDE

#2: Tạo một methode kiểm tra Object.

Bổ sung method vào class NullPointerExceptionTechmasterVN.java

public static boolean techmasterIsNullOrEmpty(String techmasterString) {
		if (techmasterString == null)
			return true;
		else if (techmasterString.trim().equals(""))
			return true;
		else
			return false;
	}

Ta sửa lại code lại methode TechmasterNPE2() trong class chính.

String techmasterString2 = null;
		System.out.println(techmasterString2.toString());
		
		if (!techmasterIsNullOrEmpty(techmasterString2)) {
			System.out.println(techmasterString2.toString());
		} else {
			System.out.println("techmasterString2 có giá trị null");
		}

#3: Kiểm tra String null sau lệnh thực thi trim()

public static boolean isNullOrEmptyAfterTrim(String techmasterString) {
        return (techmasterString == null || techmasterString.trim().length() == 0);
}

 

#4: Luôn sử dụng cấu trúc Try Catch bắt lỗi NullPointerException

try {
	TechmasterNPE1();
} catch (NullPointerException techmaster1) {
	System.out.println("Exception in CrunchifyNPE1()" + techmaster1);
}

#5: Sử dụng Collections.emptyList()

Collections.emptyList()

#6: Sử dụng Java Assertions

assert <Expression>; 
assert <Expression1> : <Expression2>;
 
// bổ sung thêm vào class chính
private void printName(String s) {
	assert (s != null) : "Name must be not null"; 
	System.out.println(s + " (" + s.length() + ")");
}

#7: Sử dụng containsKey(), containsValue(), contains() để kiểm tra giá trị null.

package techmaster.edu.java;

import java.util.HashMap;

public class ContainKeyExample {
	public static void main(String args[]) {
		HashMap<Integer, String> techmasterMap = new HashMap<Integer, String>();
 
		// Khởi tạo cách giá trị cho HashMap
		techmasterMap.put(1, "Ngọc Trinh");
		techmasterMap.put(2, "Angela Phương Trinh");
		techmasterMap.put(3, "Kì Duyên");
		// kiểm tra sự tồn tại của key số 4
		if (techmasterMap.containsKey(4)) {
			System.out.println("Nếu key 2 tồn tại thì: " + techmasterMap.get(4));
		} else {
			System.out.println("Tránh được lỗi NullPointerException cho key 4");
		}
	}
}

Chạy thử class trên, bạn sẽ ra kết quả in chuỗi: "Tránh được lỗi NullPointerException cho key 4".

#8: Viết code thật khôn ngoan:

Hãy cùng xem hai đoạn code dưới đây:

public boolean checkName(String name) {
    return name.equalsIgnoreCase("Tăng Thanh Hà");
}

Khi biến name trong methode trên là null, chúng ta sẽ gặp lỗi NullPointerException.

Có thể khắc phục theo cách sau:


public boolean checkName(String name) {
    return "Tăng Thanh Hà".equalsIgnoreCase(name);
}

Chuỗi String "Tăng Thanh Hà" được đặt ở đầu là một đối tượng không bao giờ null nên khi chúng ta 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.

Hãy luyện tập các ví dụ trên thử nhé, bạn sẽ tiết kiệm được kha khá thời gian trong tương lai khi làm chủ được lỗi NullPointerException đó.

Nguồn: crunchify