Java NullPointerException – Rilevamento, Risoluzione e Migliori Pratiche

java.lang.NullPointerException è una delle più popolari eccezioni in java nella programmazione. Chiunque lavori in java deve aver visto questo apparire dal nulla nel programma standalone di java così come nell’applicazione web java.

java.lang.NullPointerException

NullPointerException è un’eccezione di runtime, quindi non abbiamo bisogno di catturarla nel programma. NullPointerException viene sollevata in un’applicazione quando stiamo cercando di fare qualche operazione su null dove è richiesto un oggetto. Alcune delle ragioni comuni per NullPointerException nei programmi java sono:

  1. Invocare un metodo su un’istanza di oggetto ma a runtime l’oggetto è null.
  2. Accedere a variabili di un’istanza di oggetto che è null a runtime.
  3. Lanciare null nel programma
  4. Accedere all’indice o modificare il valore di un indice di un array che è null
  5. Controllare la lunghezza di un array che è null a runtime.

Esempi di Java NullPointerException

Diamo un’occhiata ad alcuni esempi di NullPointerException nei programmi Java.

1. NullPointerException durante la chiamata di un metodo di istanza

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

Quando eseguiamo il programma sopra, viene generato il seguente messaggio di errore NullPointerException.

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

Ottieniamo NullPointerException nella dichiarazione t.foo("Ciao"); perché “t” è null in questo punto.

2. Java NullPointerException durante l’accesso/modifica di un campo di un oggetto 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;
	}

}

Il programma sopra genera la seguente traccia di stack NullPointerException.

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

NullPointerException viene generata nella dichiarazione int i = t.x; perché “t” è null in questo punto.

3. Java NullPointerException quando viene passato null come argomento del metodo

public class Temp {

	public static void main(String[] args) {

		foo(null);

	}

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

Questo è uno degli eventi più comuni di `java.lang.NullPointerException` perché è chi chiama a passare l’argomento nullo.

L’immagine sottostante mostra l’eccezione del puntatore nullo quando il programma precedente viene eseguito nell’IDE Eclipse.

4. java.lang.NullPointerException quando viene lanciato il null

public class Temp {

	public static void main(String[] args) {

		throw null;
	}

}

Sotto è la traccia dello stack dell’eccezione del programma precedente, mostrando NullPointerException a causa dell’istruzione `throw null;`.

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

5. NullPointerException quando si ottiene la lunghezza di un array nullo

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 quando si accede al valore dell’indice di un array nullo

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 quando sincronizzato su un oggetto nullo

public class Temp {

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

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

Il synchronized(mutex) genererà una NullPointerException perché l’oggetto “mutex” è nullo.

8. Stato HTTP 500 java.lang.NullPointerException

A volte otteniamo una risposta di pagina di errore da un’applicazione web Java con un messaggio di errore come “Stato HTTP 500 – Errore interno del server” e la causa principale è java.lang.NullPointerException.

Per questo, ho modificato il progetto dell’Esempio Spring MVC e ho modificato il metodo HomeController come segue.

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

Nell’immagine sottostante è mostrato il messaggio di errore generato dalla risposta dell’applicazione web.

Ecco la traccia delle eccezioni:

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 causa principale è NullPointerException nella dichiarazione user.getUserId().toLowerCase() perché user.getUserId() restituisce null.

Come rilevare java.lang.NullPointerException

Rilevare NullPointerException è molto facile, basta guardare la traccia dell’eccezione e ti mostrerà il nome della classe e il numero di riga dell’eccezione. Poi guarda il codice e vedi cosa potrebbe essere nullo causando il NullPointerException. Basta guardare tutti gli esempi precedenti, è molto chiaro dalla traccia dello stack cosa sta causando l’eccezione del puntatore nullo.

Come risolvere NullPointerException

java.lang.NullPointerException è un’eccezione non controllata, quindi non dobbiamo catturarla. Le eccezioni del puntatore nullo possono essere prevenute utilizzando controlli null e tecniche di codifica preventive. Guarda gli esempi di codice qui sotto che mostrano come evitare java.lang.NullPointerException.

if(mutex ==null) mutex =""; //codifica preventiva
		
synchronized(mutex) {
	System.out.println("synchronized block");
}
//utilizzo di controlli 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());
}

Pratiche migliori di codifica per evitare NullPointerException

1. Consideriamo la funzione sottostante e cerchiamo di individuare lo scenario che causa un’eccezione di puntatore nullo.

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

La NullPointerException può verificarsi se viene passato un argomento come null. Lo stesso metodo può essere scritto come segue per evitare NullPointerException.

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

2. Possiamo anche aggiungere un controllo null per l’argomento e lanciare IllegalArgumentException se necessario.

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

3. Possiamo usare l’operatore ternario come mostrato nell’esempio di codice sottostante.

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

4. Utilizzare String.valueOf() piuttosto che il metodo toString(). Ad esempio, controlla che il codice del metodo PrintStream println() sia definito come segue.

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

Il frammento di codice sottostante mostra l’esempio in cui viene utilizzato il metodo valueOf() invece di toString().

Object mutex = null;

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

//genererà java.lang.NullPointerException
System.out.println(mutex.toString());

5. Scrivere metodi che restituiscano oggetti vuoti anziché null ovunque possibile, ad esempio, lista vuota, stringa vuota, ecc.

6. Ci sono alcuni metodi definiti nelle classi di raccolta per evitare NullPointerException, dovresti utilizzarli. Ad esempio contains(), containsKey(), e containsValue().

Riferimento: Documento API

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