Czy zauważyłeś wyjątek java.lang.NullPointerException (NPE)? 8 najlepszych praktyk, aby uniknąć NPE w środowisku uruchomieniowym w Javie
Opublikowany: 2020-10-07
Unikaj wyjątku Null Pointer Exception w Javie i Java Wskazówki i najlepsze praktyki, aby uniknąć NullPointerException w Javie.
Jestem pewien, że jako programista Java musiałeś stawić czoła wyjątkowi Null Pointer Exception (NPE) od pierwszego dnia. W większości przypadków wyjątek NPE pokazuje wyraźny ślad stosu, który wskazuje pierwotną przyczynę tego samego, ale w przypadku dużych aplikacji na poziomie Enterprise, w których masz setki klas, znalezienie prawdziwej przyczyny źródłowej staje się koszmarem.
Co to jest wyjątek wskaźnika zerowego (NPE)?
NullPointerException (NPE)
to wyjątek, który występuje, gdy próbujesz użyć odwołania, które wskazuje na brak lokalizacji w pamięci (null), tak jakby odwołuje się do obiektu.
Wywołanie metody na odwołaniu o null
lub próba uzyskania dostępu do pola odwołania o wartości NULL spowoduje wyzwolenie NPE. To najczęstsza przyczyna.
Zgodnie z JavaDoc, poniżej znajdują się główne przyczyny NPE:
- Zgłaszanie
null
tak, jakby była to wartośćThrowable
. - Wywołanie metody wystąpienia obiektu o
null
. - Uzyskiwanie dostępu lub modyfikowanie pola obiektu o
null
. - Przyjmowanie długości
null
tak, jakby była tablicą. - Uzyskiwanie dostępu do gniazd
null
lub modyfikowanie ich tak, jakby to była tablica.
Teraz prawdziwe pytanie brzmi: Jak uniknąć java.lang.NullPointerException w czasie wykonywania? W tym samouczku przyjrzymy się kilku przykładom, które tworzą NPE w czasie wykonywania i krokom, które musimy wykonać, aby rozwiązać ten problem.
Utwórzmy NPE w czasie wykonywania 1. Spójrz na poniższy przykład CrunchifyNullPointerExceptionTips.java
Stworzymy NPE na 3 różne sposoby
- NPE zostanie wyrzucony, jeśli próbujesz uzyskać dostęp do pustego obiektu
- NPE zostanie wyrzucony, jeśli próbujesz przekonwertować ciąg o wartości null
- NPE zostanie wyrzucony, jeśli próbujesz uzyskać dostęp do obiektu null podczas inicjalizacji klasy
Utwórz klasę 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 ( ) + ")" ) ; } } |
Wynik:
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 |
Cóż, istnieje kilka wskazówek i sztuczek, których możemy użyć, aby uniknąć wyjątku NullPointerException w czasie wykonywania. Spójrzmy.

Podpowiedź 1:
Eclipse / IntelliJ IDE spróbuje pokazać NPE w obszarze roboczym. Popraw swój kod tylko podczas programowania.

Podpowiedź 2:
Dodaj crunchifyI
sNullorEmpty
()
przed operacją na obiekcie. Dodaj to do 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 ; } |
W powyższym programie java wiersze 55 i 56 zostaną zastąpione tym.
1 2 3 4 5 6 |
String crunchifyString2 = null ; if ( ! crunchifyIsNullOrEmpty ( crunchifyString2 ) ) { System . out . println ( crunchifyString2 . toString ( ) ) ; } else { System . out . println ( "crunchifyString2 is null" ) ; } |
Podpowiedź 3:
Sprawdź, czy String ma null
lub empty po operacji trim().
1 2 3 |
public static boolean isNullOrEmptyAfterTrim ( String crunchifyStr ) { return ( crunchifyStr == null | | crunchifyStr . trim ( ) . length ( ) == 0 ) ; } |
Podpowiedź 4:
Zawsze używaj Try Catch block
, aby zapobiec nieprzerwanemu procesowi w czasie wykonywania.
1 2 3 4 5 |
try { CrunchifyNPE1 ( ) ; } catch ( NullPointerException npe ) { System . out . println ( "Exception in CrunchifyNPE1()" + npe ) ; } |
Podpowiedź 5:
Collections.emptyList()
jest preferowana ze względu na lepszą obsługę generyków.
Podpowiedź 6:
Użyj Java Assertions
Asercja to instrukcja, która umożliwia przetestowanie założeń dotyczących kodu. Na przykład, jeśli piszesz metodę, która zwraca nazwę w systemie, możesz stwierdzić, że zwracana nazwa otherName, jeśli String ma wartość null.
Podstawowym zastosowaniem asercji byłoby:
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 ( ) + ")" ) ; } |
Ale jest pewien haczyk: asercja nie jest dostępna w środowisku produkcyjnym i nie powinniśmy używać asercji z żadną logiką biznesową.
Podpowiedź 7:
Spróbuj użyć kontroli 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" ) ; } } } |
Podpowiedź 8:
Podsumowując, zawsze dobrą praktyką jest dbanie o NPE podczas opracowywania, a raczej debugowanie w środowisku produkcyjnym w czasie wykonywania. Istnieje wiele innych wskazówek i sztuczek dostępnych przy użyciu adnotacji Spring Framework, Factory Pattern
obiektu zerowego itp. Ale teraz to skrócę.
Opublikuję nowy samouczek prawdopodobnie za tydzień na ten. Bądźcie czujni.
Czy chcesz coś dodać do tego samouczka LUB znaleźć problem, włącz się i podaj swoje komentarze.