คุณสังเกตเห็น java.lang.NullPointerException (NPE) หรือไม่ 8 แนวทางปฏิบัติที่ดีที่สุดเพื่อหลีกเลี่ยงรันไทม์ NPE ใน Java
เผยแพร่แล้ว: 2020-10-07
หลีกเลี่ยง Null Pointer Exception ใน Java และ Java Tips และแนวทางปฏิบัติที่ดีที่สุดเพื่อหลีกเลี่ยง NullPointerException ใน Java
ในฐานะนักพัฒนา Java ฉันแน่ใจว่าคุณต้องเผชิญกับ Null Pointer Exception (NPE) ตั้งแต่วันแรก ในกรณีส่วนใหญ่ข้อยกเว้นของ NPE แสดงการติดตามสแต็กที่ชัดเจนซึ่งพินชี้สาเหตุรากของสิ่งเดียวกัน แต่ในกรณีของแอปพลิเคชันระดับองค์กรขนาดใหญ่ที่คุณมีคลาสหลายร้อยคลาส การค้นหาสาเหตุที่แท้จริงจะกลายเป็นฝันร้าย
ข้อยกเว้นตัวชี้ Null (NPE) คืออะไร?
NullPointerException (NPE)
เป็นข้อยกเว้นที่เกิดขึ้นเมื่อคุณพยายามใช้การอ้างอิงที่ชี้ไปยังตำแหน่งที่ไม่มีในหน่วยความจำ (null) ราวกับว่ามันถูกอ้างอิงถึงวัตถุ
การเรียกใช้เมธอดบนการอ้างอิง null
หรือพยายามเข้าถึงฟิลด์ของการอ้างอิงค่า null จะทริกเกอร์ NPE นี่เป็นสาเหตุที่พบบ่อยที่สุด
ตาม JavaDoc ด้านล่างเป็นสาเหตุหลักของ NPE:
- โยน
null
ราวกับว่ามันเป็นค่าThrowable
- การเรียกเมธอดอินสแตนซ์ของอ็อบเจกต์
null
- การเข้าถึงหรือแก้ไขฟิลด์ของวัตถุ
null
- ใช้ความยาวของ
null
ราวกับว่าเป็นอาร์เรย์ - การเข้าถึงหรือแก้ไขสล็อตของ
null
ราวกับว่าเป็นอาร์เรย์
ตอนนี้คำถามที่แท้จริงคือจะหลีกเลี่ยง java.lang.NullPointerException ที่รันไทม์ได้อย่างไร ในบทช่วยสอนนี้ เราจะดูตัวอย่างบางส่วนที่สร้าง NPE ขณะรันไทม์และขั้นตอนที่เราจำเป็นต้องดำเนินการเพื่อแก้ไขปัญหานี้
มาสร้าง NPE กันที่รันไทม์ที่ 1 กัน ดูตัวอย่างด้านล่าง CrunchifyNullPointerExceptionTips.java
เราจะสร้าง NPE 3 วิธีที่แตกต่างกัน
- NPE จะถูกโยนทิ้งหากคุณพยายามเข้าถึง null Object
- NPE จะถูกโยนทิ้งหากคุณพยายามแปลงค่า null String
- NPE จะถูกโยนทิ้งหากคุณพยายามเข้าถึง null Object ระหว่างการเริ่มต้นคลาส
สร้างคลาส 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 ( ) + ")" ) ; } } |
ผลลัพธ์:
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 |
มีเคล็ดลับและกลเม็ดเล็ก ๆ น้อย ๆ ที่เราสามารถใช้เพื่อหลีกเลี่ยง NullPointerException ที่รันไทม์ได้ ลองมาดูกัน

คำแนะนำ 1:
Eclipse / IntelliJ IDE จะพยายามแสดง NPE ในพื้นที่ทำงาน แก้ไขรหัสของคุณในระหว่างการพัฒนาเท่านั้น

คำแนะนำ 2:
เพิ่ม crunchifyI
sNullorEmpty
()
ตรวจสอบก่อนดำเนินการกับวัตถุ เพิ่มลงใน 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 ; } |
ในบรรทัดโปรแกรม Java ด้านบน 55 และ 56 จะถูกแทนที่ด้วยสิ่งนี้
1 2 3 4 5 6 |
String crunchifyString2 = null ; if ( ! crunchifyIsNullOrEmpty ( crunchifyString2 ) ) { System . out . println ( crunchifyString2 . toString ( ) ) ; } else { System . out . println ( "crunchifyString2 is null" ) ; } |
คำแนะนำ 3:
ตรวจสอบว่า String เป็น null
หลังจากการดำเนินการ trim()
1 2 3 |
public static boolean isNullOrEmptyAfterTrim ( String crunchifyStr ) { return ( crunchifyStr == null | | crunchifyStr . trim ( ) . length ( ) == 0 ) ; } |
คำแนะนำ 4:
ใช้ Try Catch block
เสมอ เพื่อป้องกันกระบวนการรันไทม์อย่างต่อเนื่อง
1 2 3 4 5 |
try { CrunchifyNPE1 ( ) ; } catch ( NullPointerException npe ) { System . out . println ( "Exception in CrunchifyNPE1()" + npe ) ; } |
คำแนะนำ 5:
Collections.emptyList()
เป็นที่ต้องการเนื่องจากการจัดการยาชื่อสามัญได้ดีกว่า
คำแนะนำ 6:
ใช้ Java Assertions
การยืนยันเป็นคำสั่งที่ช่วยให้คุณสามารถทดสอบสมมติฐานของคุณเกี่ยวกับโค้ดของคุณได้ ตัวอย่างเช่น หากคุณเขียนวิธีการที่ส่งกลับชื่อในระบบ คุณอาจยืนยันว่าการส่งคืน otherName ถ้าสตริงเป็นค่าว่าง
การใช้การยืนยันขั้นพื้นฐานจะเป็น:
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 ( ) + ")" ) ; } |
แต่มีสิ่งที่จับได้: การยืนยันไม่พร้อมใช้งานในสภาพแวดล้อมการใช้งานจริง และเราไม่ควรใช้การยืนยันกับตรรกะทางธุรกิจใดๆ
คำแนะนำ 7:
ลองใช้ 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" ) ; } } } |
คำแนะนำ 8:
โดยสรุปแล้ว แนวทางปฏิบัติที่ดีเสมอในการดูแล NPE ระหว่างการพัฒนา แทนที่จะดีบั๊กในการผลิตที่รันไทม์ มีเคล็ดลับและลูกเล่นอื่นๆ อีกจำนวนหนึ่งที่ใช้ได้โดยใช้ Spring Framework Annotation, Factory Pattern
, Null Object Pattern เป็นต้น แต่ฉันจะย่อให้สั้นกว่านี้
จะเผยแพร่บทช่วยสอนใหม่น่าจะในหนึ่งสัปดาห์เกี่ยวกับบทช่วยสอนนี้ คอยติดตาม.
คุณต้องการเพิ่มเติมอะไรในบทช่วยสอนนี้ หรือพบปัญหา โปรดพูดคุยและแสดงความคิดเห็นของคุณ