Hai notato java.lang.NullPointerException (NPE)? 8 migliori pratiche per evitare NPE di runtime in Java
Pubblicato: 2020-10-07
Evitare Null Pointer Exception in Java e Java Suggerimenti e procedure consigliate per evitare NullPointerException in Java.
Come sviluppatore Java, sono sicuro che devi aver affrontato Null Pointer Exception (NPE) a partire dal 1° giorno. Nella maggior parte dei casi l'eccezione NPE mostra una chiara traccia dello stack che indica la causa principale dello stesso, ma in caso di applicazioni di livello Enterprise di grandi dimensioni in cui hai centinaia di classi, diventa un incubo scoprire la vera causa principale.
Che cos'è l'eccezione del puntatore nullo (NPE)?
NullPointerException (NPE)
è un'eccezione che si verifica quando si tenta di utilizzare un riferimento che non punta a nessuna posizione in memoria (null) come se facesse riferimento a un oggetto.
La chiamata a un metodo su un riferimento null
o il tentativo di accedere a un campo di un riferimento null attiverà un NPE. Questa è la causa più comune.
Secondo JavaDoc, di seguito sono riportate le principali cause di NPE:
- Lanciando
null
come se fosse un valoreThrowable
. - Chiamare il metodo di istanza di un oggetto
null
. - Accesso o modifica del campo di un oggetto
null
. - Prendendo la lunghezza di
null
come se fosse un array. - Accedere o modificare gli slot di
null
come se fosse un array.
Ora la vera domanda è come evitare java.lang.NullPointerException in runtime? In questo tutorial esamineremo alcuni esempi che creano NPE in fase di esecuzione e i passaggi che dobbiamo eseguire per risolverlo.
Creiamo NPE al runtime 1st. Dai un'occhiata all'esempio seguente CrunchifyNullPointerExceptionTips.java
Creeremo NPE 3 modi diversi
- NPE verrà generato se stai tentando di accedere a null Object
- NPE verrà generato se stai cercando di convertire String null
- NPE verrà generato se si sta tentando di accedere a null Object durante l'inizializzazione della classe
Crea classe CrunchifyNullPointerExceptionTips.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
package crunchify . com . tutorial ; /** * @author Crunchify.com * Have you Noticed java.lang.NullPointerException (NPE)? 8 Best practices to avoid runtime NPE in Java */ public class CrunchifyNullPointerExceptionTips { public static void main ( String [ ] args ) { try { // Example 1: NPE will be thrown if you are trying to access null Object CrunchifyNPE1 ( ) ; } catch ( NullPointerException crunchifyNPE1 ) { System . out . println ( "Exception in CrunchifyNPE1()" ) ; crunchifyNPE1 . printStackTrace ( ) ; } try { // Example 2: NPE will be thrown if you are trying to convert null String CrunchifyNPE2 ( ) ; } catch ( NullPointerException crunchifyNPE2 ) { System . out . println ( "\nException in CrunchifyNPE2()" ) ; // printStackTrace(): Prints this throwable and its backtrace to the standard error stream. // This method prints a stack trace for this Throwable object on the error output stream that is the value of the field System.err. // The first line of output contains the result of the toString() method for this object. // Remaining lines represent data previously recorded by the method fillInStackTrace(). crunchifyNPE2 . printStackTrace ( ) ; } try { // Example 3: NPE will be thrown if you are trying to access null Object during Class Initialization CrunchifyNPETest npe = new CrunchifyNPETest ( ) ; npe . getName ( ) ; // NullPointerException: Thrown when an application attempts to use null in a case where an object is required. These include: // - Calling the instance method of a null object. // - Accessing or modifying the field of a null object. // - Taking the length of null as if it were an array. // - Accessing or modifying the slots of null as if it were an array. // - Throwing null as if it were a Throwable value. } catch ( NullPointerException crunchifyNPE3 ) { System . out . println ( "\n Exception in CrunchifyNPETest()" ) ; crunchifyNPE3 . printStackTrace ( ) ; } } private static void CrunchifyNPE1 ( ) { Object crunchifyObj = null ; // hasCode(): Returns a hash code value for the object. // This method is supported for the benefit of hash tables such as those provided by java.util.HashMap. crunchifyObj . hashCode ( ) ; } private static void CrunchifyNPE2 ( ) { String crunchifyString ; crunchifyString = "https://crunchify.com" ; // The line 40 declares a variable named "crunchifyString", but, it does not contain a primitive value. Instead it contains a pointer (because the type is String // which is a reference type). Since you did not say as yet what to point to Java sets it to null, meaning "I am pointing at nothing". // In line 41, the new keyword is used to instantiate (or create) an object of type String and the pointer variable "crunchifyString" is assigned this // object. You can now reference the object using the dereferencing operator . (a dot). System . out . println ( "\nvalue: " + crunchifyString . toString ( ) + ", length: " + crunchifyString . length ( ) ) ; System . out . println ( "No NPE exception on line 51" ) ; // Now Let's create NPE String crunchifyString2 = null ; System . out . println ( crunchifyString2 . toString ( ) ) ; } } class CrunchifyNPETest { private String crunchifyName ; public void setName ( String name ) { this . crunchifyName = name ; } public void getName ( ) { printName ( crunchifyName ) ; } private void printName ( String s ) { System . out . println ( s + " (" + s . length ( ) + ")" ) ; } } |
Risultato:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Exception in CrunchifyNPE1 ( ) java . lang . NullPointerException : Cannot invoke "Object.hashCode()" because "crunchifyObj" is null at crunchify . com . tutorial . CrunchifyNullPointerExceptionTips . CrunchifyNPE1 ( CrunchifyNullPointerExceptionTips . java : 59 ) at crunchify . com . tutorial . CrunchifyNullPointerExceptionTips . main ( CrunchifyNullPointerExceptionTips . java : 14 ) value : https : //crunchify.com, length: 21 No NPE exception on line 51 Exception in CrunchifyNPE2 ( ) Exception in CrunchifyNPETest ( ) java . lang . NullPointerException : Cannot invoke "String.toString()" because "crunchifyString2" is null at crunchify . com . tutorial . CrunchifyNullPointerExceptionTips . CrunchifyNPE2 ( CrunchifyNullPointerExceptionTips . java : 75 ) at crunchify . com . tutorial . CrunchifyNullPointerExceptionTips . main ( CrunchifyNullPointerExceptionTips . java : 23 ) java . lang . NullPointerException : Cannot invoke "String.length()" because "s" is null at crunchify . com . tutorial . CrunchifyNPETest . printName ( CrunchifyNullPointerExceptionTips . java : 92 ) at crunchify . com . tutorial . CrunchifyNPETest . getName ( CrunchifyNullPointerExceptionTips . java : 88 ) at crunchify . com . tutorial . CrunchifyNullPointerExceptionTips . main ( CrunchifyNullPointerExceptionTips . java : 38 ) Process finished with exit code 0 |
Bene, ci sono alcuni suggerimenti e trucchi che potremmo usare per evitare NullPointerException in fase di esecuzione. Diamo un'occhiata.

Suggerimento 1:
Eclipse / IntelliJ IDE proverà a mostrare NPE nell'area di lavoro. Correggi il codice solo durante lo sviluppo.

Suggerimento 2:
Aggiungi crunchifyI
sNullorEmpty
()
prima di un'operazione sull'oggetto. Aggiungilo a CrunchifyNullPointerExceptionTips.java
1 2 3 4 5 6 7 8 |
public static boolean crunchifyIsNullOrEmpty ( String crunchifyStr ) { if ( crunchifyStr == null ) return true ; else if ( crunchifyStr . trim ( ) . equals ( "" ) ) return true ; else return false ; } |
Nella precedente riga di programma java 55 e 56 verranno sostituite con questa.
1 2 3 4 5 6 |
String crunchifyString2 = null ; if ( ! crunchifyIsNullOrEmpty ( crunchifyString2 ) ) { System . out . println ( crunchifyString2 . toString ( ) ) ; } else { System . out . println ( "crunchifyString2 is null" ) ; } |
Suggerimento 3:
Controlla se String è null
di vuoto dopo l'operazione trim().
1 2 3 |
public static boolean isNullOrEmptyAfterTrim ( String crunchifyStr ) { return ( crunchifyStr == null | | crunchifyStr . trim ( ) . length ( ) == 0 ) ; } |
Suggerimento 4:
Utilizzare sempre il Try Catch block
per prevenire un processo di runtime ininterrotto.
1 2 3 4 5 |
try { CrunchifyNPE1 ( ) ; } catch ( NullPointerException npe ) { System . out . println ( "Exception in CrunchifyNPE1()" + npe ) ; } |
Suggerimento 5:
Collections.emptyList()
è preferito per una migliore gestione dei generici.
Suggerimento 6:
Usa Java Assertions
Un'asserzione è un'affermazione che ti consente di testare le tue ipotesi sul tuo codice. Ad esempio, se si scrive un metodo che restituisce il nome nel sistema, è possibile affermare che la restituzione di otherName se String è null.
L'uso di base delle asserzioni sarebbe:
1 2 3 4 5 6 7 8 |
assert < Expression > ; // or another usage is assert < Expression1 > : < Expression2 > ; // in our program add line below. private void printName ( String s ) { assert ( s ! = null ) : "Name must be not null" ; System . out . println ( s + " (" + s . length ( ) + ")" ) ; } |
Ma c'è un problema: l'asserzione non è disponibile nell'ambiente di produzione e non dovremmo usare l'asserzione con alcuna logica di business.
Suggerimento 7:
Prova a utilizzare i controlli containsKey()
, containsValue()
, contains()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com . crunchify . tutorial ; import java . util . * ; /** * @author Crunchify.com * */ public class CrunchifyContainsKeyExample { public static void main ( String args [ ] ) { HashMap < Integer , String > crunchifyMap = new HashMap < Integer , String > ( ) ; // populate hash map crunchifyMap . put ( 1 , "Crunchify" ) ; crunchifyMap . put ( 2 , "wordpress" ) ; crunchifyMap . put ( 3 , "java tutorials" ) ; // check existence of key 4 if ( crunchifyMap . containsKey ( 4 ) ) { System . out . println ( "Check if key 2 exists: " + crunchifyMap . get ( 4 ) ) ; } else { System . out . println ( "NPE for value 4 avoided" ) ; } } } |
Suggerimento 8:
In conclusione, è sempre buona norma occuparsi di NPE durante lo sviluppo piuttosto che eseguire il debug in produzione in fase di runtime. Ci sono molti altri suggerimenti e trucchi disponibili usando Spring Framework Annotation, Factory Pattern
, Null Object Pattern ecc. Ma ora taglierò questo corto.
Pubblicherà un nuovo tutorial probabilmente tra una settimana su questo. Rimani sintonizzato.
Vuoi aggiungere qualcosa a questo tutorial O hai riscontrato un problema, per favore intervieni e fornisci i tuoi commenti.