Java NullPointerException – Détecter, corriger et meilleures pratiques

java.lang.NullPointerException est l’une des exceptions les plus populaires en Java. Toute personne travaillant en Java a dû voir cela surgir de nulle part dans le programme autonome Java ainsi que dans l’ application web Java.

java.lang.NullPointerException

NullPointerException est une exception d’exécution, donc nous n’avons pas besoin de la capturer dans le programme. NullPointerException est levée dans une application lorsque nous essayons d’effectuer une opération sur null où un objet est requis. Certaines des raisons courantes de NullPointerException dans les programmes Java sont:

  1. Appeler une méthode sur une instance d’objet mais à l’exécution l’objet est null.
  2. Accéder à des variables d’une instance d’objet qui est null à l’exécution.
  3. Lancer null dans le programme
  4. Accéder à un index ou modifier la valeur d’un index d’un tableau qui est null
  5. Vérifier la longueur d’un tableau qui est null à l’exécution.

Exemples de NullPointerException en Java

Regardons quelques exemples de NullPointerException dans les programmes Java.

1. NullPointerException lors de l’appel d’une méthode d’instance

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());
	}
}

Lorsque nous exécutons le programme ci-dessus, il génère le message d’erreur NullPointerException suivant.

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

Nous obtenons une NullPointerException dans l’instruction t.foo("Hi"); car « t » est nul ici.

2. Java NullPointerException lors de l’accès/modification d’un champ d’un objet null

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;
	}

}

Le programme ci-dessus génère la trace de pile suivante pour NullPointerException.

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

NullPointerException est déclenchée dans l’instruction int i = t.x; car « t » est nul ici.

3. Java NullPointerException lorsqu’un null est passé en argument de méthode

public class Temp {

	public static void main(String[] args) {

		foo(null);

	}

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

Voici l’un des cas les plus courants de la java.lang.NullPointerException car c’est l’appelant qui passe l’argument nul.

L’image ci-dessous montre l’exception de pointeur nul lorsque le programme ci-dessus est exécuté dans Eclipse IDE.

4. java.lang.NullPointerException lorsqu’un nul est lancé

public class Temp {

	public static void main(String[] args) {

		throw null;
	}

}

Ci-dessous se trouve la trace de la pile d’exceptions du programme ci-dessus, montrant une NullPointerException en raison de l’instruction throw null;.

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

5. NullPointerException lors de la récupération de la longueur d’un tableau nul

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 lors de l’accès à la valeur d’indice d’un tableau nul

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 lors de la synchronisation sur un objet null

public class Temp {

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

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

Le synchronized(mutex) va générer une NullPointerException car l’objet « mutex » est null.

8. HTTP Status 500 java.lang.NullPointerException

Parfois, nous recevons une réponse de page d’erreur d’une application web Java avec un message d’erreur tel que « HTTP Status 500 – Internal Server Error » et la cause principale est java.lang.NullPointerException.

Pour cela, j’ai modifié le projet Exemple Spring MVC et changé la méthode HomeController comme suit.

@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";
	}

L’image ci-dessous montre le message d’erreur généré par la réponse de l’application web.

Voici la trace de la pile d’exceptions:

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)

La cause principale est une NullPointerException dans l’instruction user.getUserId().toLowerCase() car user.getUserId() renvoie null.

Comment détecter java.lang.NullPointerException

Détecter NullPointerException est très facile, il suffit de regarder la trace de l’exception et elle vous montrera le nom de la classe et le numéro de ligne de l’exception. Ensuite, regardez le code et voyez ce qui pourrait être nul causant le NullPointerException. Il suffit de regarder tous les exemples ci-dessus, il est très clair à partir de la trace de la pile ce qui cause une exception de pointeur nul.

Comment réparer NullPointerException

java.lang.NullPointerException est une exception non contrôlée, donc nous n’avons pas besoin de l’attraper. Les exceptions de pointeur nul peuvent être évitées en utilisant des vérifications de null et des techniques de codage préventives. Regardez ci-dessous des exemples de code montrant comment éviter java.lang.NullPointerException.

if(mutex ==null) mutex =""; //codage préventif
		
synchronized(mutex) {
	System.out.println("synchronized block");
}
//utilisation de vérifications de null
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());
}

Pratiques de codage recommandées pour éviter NullPointerException

1. Considérons la fonction ci-dessous et recherchons les scénarios provoquant une exception de pointeur nul.

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

La NullPointerException peut survenir si l’argument est passé comme null. La même méthode peut être écrite comme suit pour éviter la NullPointerException.

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

2. Nous pouvons également ajouter une vérification de null pour l’argument et déclencher une IllegalArgumentException si nécessaire.

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

3. Nous pouvons utiliser l’opérateur ternaire comme illustré dans l’exemple de code ci-dessous.

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

4. Utilisez String.valueOf() plutôt que la méthode toString(). Par exemple, vérifiez le code de la méthode PrintStream println() défini comme suit.

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

Le fragment de code ci-dessous montre l’exemple où la méthode valueOf() est utilisée au lieu de toString().

Object mutex = null;

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

//lèvera java.lang.NullPointerException
System.out.println(mutex.toString());

5. Écrivez des méthodes renvoyant des objets vides plutôt que null lorsque c’est possible, par exemple, une liste vide, une chaîne vide, etc.

6. Il existe des méthodes définies dans les classes de collection pour éviter la NullPointerException, vous devriez les utiliser. Par exemple, contains(), containsKey(), et containsValue().

Référence: Document d’API

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