Java NullPointerException – Detecteren, Oplossen en Beste Praktijken

java.lang.NullPointerException is een van de meest populaire uitzonderingen in java programmering. Iedereen die in java werkt, moet dit uit het niets hebben zien opduiken in het standalone java-programma en de java-webtoepassing.

java.lang.NullPointerException

NullPointerException is een runtime-uitzondering, dus we hoeven deze niet in het programma te vangen. NullPointerException wordt in een applicatie opgeworpen wanneer we een bewerking proberen uit te voeren op null waar een object vereist is. Enkele van de meest voorkomende redenen voor NullPointerException in java-programma’s zijn:

  1. Een methode aanroepen op een objectinstantie, maar tijdens runtime is het object null.
  2. Variabelen van een objectinstantie die tijdens runtime null zijn, openen.
  3. Null in het programma gooien
  4. Index toegang of waarde van een index van een array die null is, wijzigen
  5. De lengte van een array die tijdens runtime null is, controleren.

Voorbeelden van Java NullPointerException

Laten we eens kijken naar enkele voorbeelden van NullPointerException in Java-programma’s.

1. NullPointerException bij het aanroepen van een instantiemethode

public class Temp {

	public static void main(String[] args) {

		Temp t = initT();
		
		t.foo("Hi");
		
	}

	private static Temp initT() {
		return null;
	}

	public void foo(String s) {
		System.out.println(s.toLowerCase());
	}
}

Wanneer we het bovenstaande programma uitvoeren, werpt het de volgende NullPointerException-foutmelding op.

Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:7)

We krijgen een NullPointerException in de verklaring t.foo("Hi"); omdat “t” hier null is.

2. Java NullPointerException bij toegang/wijziging van een veld van een null-object

public class Temp {

	public int x = 10;
	
	public static void main(String[] args) {

		Temp t = initT();
		
		int i = t.x;
		
	}

	private static Temp initT() {
		return null;
	}

}

Het bovenstaande programma werpt de volgende NullPointerException-stacktrace op.

Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:9)

NullPointerException wordt veroorzaakt in de verklaring int i = t.x; omdat “t” hier null is.

3. Java NullPointerException wanneer null wordt doorgegeven als methode-argument

public class Temp {

	public static void main(String[] args) {

		foo(null);

	}

	public static void foo(String s) {
		System.out.println(s.toLowerCase());
	}
}

Dit is een van de meest voorkomende gevallen van `java.lang.NullPointerException`, omdat het de aanroeper is die het nulargument doorgeeft.

De onderstaande afbeelding toont de null pointer-uitzondering wanneer het bovenstaande programma wordt uitgevoerd in Eclipse IDE.

4. java.lang.NullPointerException wanneer null wordt gegenereerd

public class Temp {

	public static void main(String[] args) {

		throw null;
	}

}

Hieronder staat de stacktrace van de uitzondering van het bovenstaande programma, die een NullPointerException laat zien vanwege de `throw null;`-verklaring.

Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:5)

5. NullPointerException bij het ophalen van de lengte van een null-array

public class Temp {

	public static void main(String[] args) {

		int[] data = null;
		
		int len = data.length;
	}

}
Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:7)

6. NullPointerException bij het openen van de indexwaarde van een null-array

public class Temp {

	public static void main(String[] args) {

		int[] data = null;
		
		int len = data[2];
	}

}
Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:7)

7. NullPointerException bij synchronisatie op een null object

public class Temp {

	public static String mutex = null;
	
	public static void main(String[] args) {

		synchronized(mutex) {
			System.out.println("synchronized block");
		}		
	}
}

De synchronized(mutex) zal een NullPointerException veroorzaken omdat het “mutex”-object null is.

8. HTTP-status 500 java.lang.NullPointerException

Soms krijgen we een foutpagina-reactie van een Java-webtoepassing met een foutmelding als “HTTP-status 500 – Interne serverfout” en als hoofdoorzaak java.lang.NullPointerException.

Voor dit probleem heb ik de Spring MVC-voorbeeld-project aangepast en de HomeController-methode als volgt gewijzigd.

@RequestMapping(value = "/user", method = RequestMethod.POST)
	public String user(@Validated User user, Model model) {
		System.out.println("User Page Requested");
		System.out.println("User Name: "+user.getUserName().toLowerCase());
		System.out.println("User ID: "+user.getUserId().toLowerCase());
		model.addAttribute("userName", user.getUserName());
		return "user";
	}

De onderstaande afbeelding toont de foutmelding die wordt gegenereerd door de reactie van de webtoepassing.

Hier is de uitzonderings-stacktrace:

HTTP Status 500Internal Server Error

Type Exception Report

Message Request processing failed; nested exception is java.lang.NullPointerException

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
	org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Root Cause

java.lang.NullPointerException
	com.journaldev.spring.controller.HomeController.user(HomeController.java:38)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	java.lang.reflect.Method.invoke(Method.java:498)

De hoofdoorzaak is een NullPointerException in de instructie user.getUserId().toLowerCase() omdat user.getUserId() null retourneert.

Hoe een java.lang.NullPointerException te detecteren

Het detecteren van een NullPointerException is erg eenvoudig, kijk gewoon naar de uitzonderingstrace en het zal je de naam van de klasse en het regelnummer van de uitzondering tonen. Kijk dan naar de code en zie wat mogelijk null kan zijn waardoor de NullPointerException wordt veroorzaakt. Kijk gewoon naar alle bovenstaande voorbeelden, het is heel duidelijk uit de stacktrace wat de nullpointeruitzondering veroorzaakt.

Hoe NullPointerException te repareren

java.lang.NullPointerException is een ongecontroleerde uitzondering, dus we hoeven het niet te vangen. De null pointer-uitzonderingen kunnen worden voorkomen door null-controles en preventieve codeertechnieken te gebruiken. Bekijk hieronder codevoorbeelden die laten zien hoe je java.lang.NullPointerException kunt vermijden.

if(mutex ==null) mutex =""; // preventieve codering
		
synchronized(mutex) {
	System.out.println("synchronized block");
}
// met behulp van null-controles
if(user!=null && user.getUserName() !=null) {
System.out.println("User Name: "+user.getUserName().toLowerCase());
}
if(user!=null && user.getUserName() !=null) {
	System.out.println("User ID: "+user.getUserId().toLowerCase());
}

Beste coderingspraktijken om NullPointerException te vermijden

1. Laten we de onderstaande functie bekijken en letten op het scenario dat een nullpointeruitzondering veroorzaakt.

public void foo(String s) {
    if(s.equals("Test")) {
	System.out.println("test");
    }
}

De NullPointerException kan optreden als het argument als null wordt doorgegeven. Dezelfde methode kan als volgt worden geschreven om NullPointerException te vermijden.

public void foo(String s) {
	if ("Test".equals(s)) {
		System.out.println("test");
	}
}

2. We kunnen ook een null-controle toevoegen voor het argument en IllegalArgumentException gooien indien nodig.

public int getArrayLength(Object[] array) {
	
	if(array == null) throw new IllegalArgumentException("array is null");
	
	return array.length;
}

3. We kunnen de ternaire operator gebruiken zoals in het onderstaande voorbeeldcode.

String msg = (str == null) ? "" : str.substring(0, str.length()-1);

4. Gebruik String.valueOf() in plaats van de toString() methode. Bijvoorbeeld controleer de code van de PrintStream println() methode die hieronder is gedefinieerd.

public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
        }
    }

Het onderstaande codefragment toont het voorbeeld waar de valueOf() methode wordt gebruikt in plaats van toString().

Object mutex = null;

//print null
System.out.println(String.valueOf(mutex));

//zal java.lang.NullPointerException gooien
System.out.println(mutex.toString());

5. Schrijf methoden die lege objecten retourneren in plaats van null waar mogelijk, bijvoorbeeld een lege lijst, lege string, enz.

6. Er zijn enkele methoden gedefinieerd in verzamelingsklassen om NullPointerException te vermijden, je zou ze moeten gebruiken. Bijvoorbeeld contains(), containsKey() en containsValue().

Referentie: API Document

Source:
https://www.digitalocean.com/community/tutorials/java-lang-nullpointerexception