ข้อยกเว้นตัวชี้ Null ( java.lang.NullPointerException
) คืออะไรและทำให้เกิดอะไร
วิธีการ / เครื่องมือใดบ้างที่สามารถใช้เพื่อระบุสาเหตุเพื่อให้คุณหยุดข้อยกเว้นจากสาเหตุที่ทำให้โปรแกรมหยุดการทำงานก่อนเวลาอันควร
ข้อยกเว้นตัวชี้ Null ( java.lang.NullPointerException
) คืออะไรและทำให้เกิดอะไร
วิธีการ / เครื่องมือใดบ้างที่สามารถใช้เพื่อระบุสาเหตุเพื่อให้คุณหยุดข้อยกเว้นจากสาเหตุที่ทำให้โปรแกรมหยุดการทำงานก่อนเวลาอันควร
คำตอบ:
เมื่อคุณประกาศตัวแปรอ้างอิง (เช่นวัตถุ) คุณกำลังสร้างตัวชี้ไปยังวัตถุจริงๆ พิจารณารหัสต่อไปนี้ที่คุณประกาศตัวแปรประเภทดั้งเดิมint
:
int x;
x = 10;
ในตัวอย่างนี้ตัวแปรx
คือint
และ Java จะเริ่มต้นให้0
กับคุณ เมื่อคุณกำหนดค่าของ10
ในบรรทัดที่สองค่าของคุณถูกเขียนลงในหน่วยความจำตำแหน่งที่อ้างถึงโดย10
x
แต่เมื่อคุณพยายามที่จะประกาศประเภทอ้างอิงมีบางสิ่งที่แตกต่างเกิดขึ้น ใช้รหัสต่อไปนี้:
Integer num;
num = new Integer(10);
บรรทัดแรกประกาศตัวแปรที่มีชื่อnum
แต่จริง ๆ แล้วยังไม่มีค่าดั้งเดิม แต่จะมีตัวชี้ (เพราะประเภทนั้นInteger
เป็นประเภทการอ้างอิง) เมื่อคุณยังไม่ได้บอกว่าจะให้ชี้ไปที่ Java ตั้งค่าnull
ซึ่งหมายความว่า " ฉันกำลังชี้ไปที่ไม่มีอะไร "
ในบรรทัดที่สองnew
คีย์เวิร์ดถูกใช้เพื่อสร้างอินสแตนซ์ (หรือสร้าง) วัตถุชนิดInteger
และตัวแปรตัวชี้num
ถูกกำหนดให้กับInteger
วัตถุนั้น
NullPointerException
เกิดขึ้นเมื่อคุณประกาศตัวแปร แต่ไม่ได้สร้างวัตถุและกำหนดให้กับตัวแปรก่อนที่จะพยายามที่จะใช้เนื้อหาของตัวแปร (เรียกว่าdereferencing ) ดังนั้นคุณกำลังชี้ไปที่สิ่งที่ไม่มีอยู่จริง
โดยปกติการลดความผิดพลาดจะเกิดขึ้นเมื่อใช้.
เพื่อเข้าถึงวิธีการหรือเขตข้อมูลหรือใช้[
เพื่อทำดัชนีอาร์เรย์
ถ้าคุณพยายามที่จะ dereference ก่อนที่จะสร้างวัตถุที่คุณได้รับnum
NullPointerException
ในกรณีเล็ก ๆ น้อย ๆ คอมไพเลอร์จะตรวจจับปัญหาและแจ้งให้คุณทราบว่า " num may not have been initialized
," แต่บางครั้งคุณอาจเขียนโค้ดที่ไม่ได้สร้างวัตถุโดยตรง
ตัวอย่างเช่นคุณอาจมีวิธีการดังต่อไปนี้:
public void doSomething(SomeObject obj) {
//do something to obj
}
ในกรณีนี้คุณไม่ได้สร้างวัตถุobj
แต่สมมติว่ามันถูกสร้างขึ้นก่อนที่doSomething()
วิธีการที่ถูกเรียก หมายเหตุเป็นไปได้ที่จะเรียกวิธีการเช่นนี้:
doSomething(null);
ซึ่งในกรณีนี้คือobj
null
หากวิธีการนี้มีวัตถุประสงค์เพื่อทำบางสิ่งบางอย่างกับวัตถุที่ส่งผ่านมันมีความเหมาะสมที่จะโยนNullPointerException
เพราะมันเป็นข้อผิดพลาดของโปรแกรมเมอร์และโปรแกรมเมอร์จะต้องใช้ข้อมูลนั้นเพื่อวัตถุประสงค์ในการแก้จุดบกพร่อง กรุณาใส่ชื่อของตัวแปรวัตถุในข้อความข้อยกเว้นเช่น
Objects.requireNonNull(a, "a");
อีกวิธีหนึ่งอาจมีบางกรณีที่วัตถุประสงค์ของวิธีการนี้ไม่เพียง แต่จะดำเนินการกับวัตถุที่ส่งผ่านเท่านั้นดังนั้นพารามิเตอร์ null อาจยอมรับได้ ในกรณีนี้คุณจะต้องตรวจสอบพารามิเตอร์ว่างและทำงานต่างกัน คุณควรอธิบายเรื่องนี้ในเอกสารประกอบ ตัวอย่างเช่นdoSomething()
สามารถเขียนเป็น:
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj == null) {
//do something
} else {
//do something else
}
}
สุดท้ายวิธีระบุข้อยกเว้น & สาเหตุโดยใช้ Stack Trace
วิธีการ / เครื่องมือใดบ้างที่สามารถใช้เพื่อระบุสาเหตุเพื่อให้คุณหยุดข้อยกเว้นจากสาเหตุที่ทำให้โปรแกรมหยุดการทำงานก่อนเวลาอันควร
Sonar ที่มี findbugs สามารถตรวจจับ NPE สามารถจับโซนาร์ยกเว้นตัวชี้โมฆะที่เกิดจาก JVM แบบไดนามิก
int a=b
สามารถโยน NPE Integer
ถ้าเป็นข มีหลายกรณีที่ทำให้เกิดความสับสนในการดีบัก
NullPointerException
ปัญหาในรหัสของคุณคือการใช้@Nullable
และการ@NotNull
เพิ่มความคิดเห็น คำตอบต่อไปนี้มีข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ แม้ว่าคำตอบนี้จะเฉพาะเจาะจงเกี่ยวกับ IntelliJ IDE แต่ก็ยังสามารถใช้กับเครื่องมืออื่น ๆ ตามที่อธิบายไว้ในความคิดเห็นของคุณ (BTW ผมไม่ได้รับอนุญาตให้แก้ไขคำตอบนี้โดยตรงบางทีผู้เขียนสามารถเพิ่มได้หรือไม่)
NullPointerException
s เป็นข้อยกเว้นที่เกิดขึ้นเมื่อคุณพยายามใช้การอ้างอิงที่ชี้ไปยังตำแหน่งในหน่วยความจำ (null) ไม่ว่าจะเป็นการอ้างอิงวัตถุ NullPointerException
เรียกวิธีการในการอ้างอิงโมฆะหรือพยายามที่จะเข้าถึงข้อมูลของอ้างอิงโมฆะจะเรียก นี่เป็นวิธีที่พบได้บ่อยที่สุด แต่มีวิธีอื่นที่แสดงไว้ในNullPointerException
หน้า javadoc
น่าจะเป็นโค้ดตัวอย่างที่เร็วที่สุดที่ฉันสามารถอธิบายเพื่อเป็นNullPointerException
:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
ในภายในบรรทัดแรกmain
ผมตั้งค่าอย่างชัดเจนObject
อ้างอิงเท่ากับobj
null
หมายความว่าฉันมีการอ้างอิง แต่ไม่ได้ชี้ไปที่วัตถุใด ๆ หลังจากนั้นฉันพยายามที่จะรักษาข้อมูลอ้างอิงราวกับว่ามันชี้ไปที่วัตถุโดยการเรียกวิธีการที่มัน นี่เป็นผลลัพธ์NullPointerException
เนื่องจากไม่มีรหัสที่จะดำเนินการในตำแหน่งที่การอ้างอิงกำลังชี้
(นี่เป็นเรื่องทางเทคนิค แต่ฉันคิดว่ามันพูดถึง: การอ้างอิงที่ชี้ไปที่โมฆะไม่เหมือนกับตัวชี้ C ที่ชี้ไปยังตำแหน่งหน่วยความจำที่ไม่ถูกต้องตัวชี้โมฆะไม่ได้ชี้ไปที่ใดซึ่งแตกต่างอย่างละเอียดกว่า ชี้ไปยังตำแหน่งที่ไม่ถูกต้อง)
null
ก่อนที่จะใช้มันเช่นนี้ ด้วยตัวแปรโลคอลคอมไพเลอร์จะตรวจจับข้อผิดพลาดนี้ แต่ในกรณีนี้มันจะไม่เกิดขึ้น บางทีนั่นอาจจะเป็นประโยชน์เพิ่มเติมสำหรับคำตอบของคุณ?
สถานที่ที่ดีที่จะเริ่มเป็นJavaDocs พวกเขาได้รับความคุ้มครองนี้:
โยนทิ้งเมื่อแอปพลิเคชันพยายามใช้ null ในกรณีที่จำเป็นต้องใช้วัตถุ เหล่านี้รวมถึง:
- การเรียกใช้วิธีการอินสแตนซ์ของวัตถุ null
- การเข้าถึงหรือแก้ไขฟิลด์ของวัตถุ null
- รับความยาวของโมฆะราวกับว่ามันเป็นอาร์เรย์
- การเข้าถึงหรือการปรับเปลี่ยนสล็อตเป็นโมฆะราวกับว่ามันเป็นอาร์เรย์
- การโยนค่า NULL เหมือนกับเป็นค่า Throwable
แอปพลิเคชันควรโยนอินสแตนซ์ของคลาสนี้เพื่อระบุการใช้งานวัตถุ null ที่ผิดกฎหมาย
เป็นกรณีที่ถ้าคุณพยายามใช้การอ้างอิงแบบ null ด้วยsynchronized
ซึ่งจะทำให้เกิดข้อยกเว้นนี้ตาม JLS :
SynchronizedStatement: synchronized ( Expression ) Block
- มิฉะนั้นถ้าค่าของ Expression เป็นโมฆะ a
NullPointerException
จะถูกโยนทิ้ง
NullPointerException
เพื่อให้คุณมี คุณจะแก้ไขได้อย่างไร ลองมาตัวอย่างง่ายๆที่พ่นNullPointerException
:
public class Printer {
private String name;
public void setName(String name) {
this.name = name;
}
public void print() {
printString(name);
}
private void printString(String s) {
System.out.println(s + " (" + s.length() + ")");
}
public static void main(String[] args) {
Printer printer = new Printer();
printer.print();
}
}
ระบุค่า Null
ขั้นตอนแรกคือการระบุว่าค่าที่จะก่อให้เกิดข้อยกเว้น สำหรับสิ่งนี้เราต้องทำการดีบัก การเรียนรู้ที่จะอ่านสแต็คเทรซเป็นสิ่งสำคัญ นี่จะแสดงให้คุณเห็นว่ามีข้อผิดพลาดเกิดขึ้นที่ไหน:
Exception in thread "main" java.lang.NullPointerException
at Printer.printString(Printer.java:13)
at Printer.print(Printer.java:9)
at Printer.main(Printer.java:19)
ที่นี่เราเห็นว่ามีการยกเว้นข้อยกเว้นในบรรทัดที่ 13 (ในprintString
วิธีการ) ดูที่เส้นและการตรวจสอบที่มีค่า null โดยการเพิ่มงบการเข้าสู่ระบบหรือใช้ดีบัก เราพบว่าs
เป็นโมฆะและการเรียกใช้length
เมธอดนั้นจะทำให้เกิดข้อยกเว้น เราจะเห็นว่าโปรแกรมหยุดการโยนข้อยกเว้นเมื่อs.length()
ถูกลบออกจากวิธีการ
ติดตามค่าที่มาจากเหล่านี้
ตรวจสอบว่าค่านี้มาจากที่ใด โดยทำตามผู้เรียกเมธอดเราจะเห็นว่าs
ถูกส่งผ่านด้วยprintString(name)
ในprint()
เมธอดและthis.name
เป็นโมฆะ
ติดตามตำแหน่งที่ควรตั้งค่าเหล่านี้
this.name
ตั้งอยู่ที่ไหน ในsetName(String)
วิธีการ ด้วยการดีบักเพิ่มเติมเราจะเห็นว่าวิธีนี้ไม่ได้ถูกเรียกใช้เลย หากมีการเรียกวิธีการตรวจสอบให้แน่ใจว่าได้ตรวจสอบลำดับที่เรียกวิธีการเหล่านี้และวิธีการตั้งค่านั้นไม่ได้ถูกเรียกใช้หลังจากวิธีการพิมพ์
นี้ก็เพียงพอที่จะทำให้เรามีวิธีการแก้ปัญหา: เพิ่มการเรียกก่อนที่จะเรียกprinter.setName()
printer.print()
ตัวแปรสามารถมีค่าเริ่มต้น (และsetName
สามารถป้องกันไม่ให้ถูกตั้งค่าเป็นโมฆะ):
private String name = "";
อย่างใดอย่างหนึ่งprint
หรือprintString
วิธีการที่สามารถตรวจสอบ nullตัวอย่างเช่น:
printString((name == null) ? "" : name);
หรือคุณสามารถออกแบบคลาสเพื่อให้name
มีค่าไม่เป็นโมฆะ :
public class Printer {
private final String name;
public Printer(String name) {
this.name = Objects.requireNonNull(name);
}
public void print() {
printString(name);
}
private void printString(String s) {
System.out.println(s + " (" + s.length() + ")");
}
public static void main(String[] args) {
Printer printer = new Printer("123");
printer.print();
}
}
ดูสิ่งนี้ด้วย:
หากคุณพยายามที่จะแก้ปัญหาและยังไม่มีวิธีแก้ปัญหาคุณสามารถโพสต์คำถามเพื่อขอความช่วยเหลือเพิ่มเติม แต่ให้แน่ใจว่าได้รวมสิ่งที่คุณได้ลองไปแล้ว อย่างน้อยที่สุดให้รวมสแต็คเทรซในคำถามและทำเครื่องหมายหมายเลขบรรทัดสำคัญในรหัส นอกจากนี้ให้ลองลดความซับซ้อนของรหัสก่อน (ดูSSCCE )
NullPointerException
(NPE)ในขณะที่คุณควรรู้ประเภท Java จะแบ่งออกเป็นชนิดดั้งเดิม ( boolean
, int
ฯลฯ ) และประเภทของการอ้างอิง ประเภทการอ้างอิงใน Java อนุญาตให้คุณใช้ค่าพิเศษnull
ซึ่งเป็นวิธีการบอกว่า "ไม่มีวัตถุ" ของ Java
A NullPointerException
ถูกส่งไปที่รันไทม์เมื่อใดก็ตามที่โปรแกรมของคุณพยายามใช้ a null
ราวกับว่าเป็นการอ้างอิงจริง ตัวอย่างเช่นถ้าคุณเขียนสิ่งนี้:
public class Test {
public static void main(String[] args) {
String foo = null;
int length = foo.length(); // HERE
}
}
คำสั่งที่ระบุว่า "ที่นี่" เป็นไปเพื่อพยายามที่จะเรียกใช้length()
วิธีการในการอ้างอิงและนี้จะโยนnull
NullPointerException
มีหลายวิธีที่คุณสามารถใช้เป็นค่าที่จะส่งผลให้null
NullPointerException
ในความเป็นจริงสิ่งเดียวที่คุณสามารถทำได้ด้วย a null
โดยไม่ทำให้ NPE คือ:
==
หรือผู้ประกอบการหรือ!=
instanceof
สมมติว่าฉันรวบรวมและเรียกใช้โปรแกรมข้างต้น:
$ javac Test.java
$ java Test
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:4)
$
การสังเกตครั้งแรก: การรวบรวมสำเร็จ! ปัญหาในโปรแกรมไม่ใช่ข้อผิดพลาดในการรวบรวม มันเป็นข้อผิดพลาดรันไทม์ (IDE บางตัวอาจเตือนโปรแกรมของคุณมักจะเกิดข้อยกเว้น ... แต่javac
คอมไพเลอร์มาตรฐานไม่ได้)
การสังเกตครั้งที่สอง: เมื่อฉันรันโปรแกรมมันจะแสดงผลสองบรรทัดของ "gobbledy-gook" ไม่ถูกต้อง!! นั่นไม่ใช่ gobbledy-gook เป็น stacktrace ... และให้ข้อมูลสำคัญที่จะช่วยคุณติดตามข้อผิดพลาดในรหัสของคุณหากคุณใช้เวลาอ่านอย่างระมัดระวัง
ดังนั้นเรามาดูสิ่งที่มันบอกว่า:
Exception in thread "main" java.lang.NullPointerException
บรรทัดแรกของการติดตามสแต็กจะบอกคุณหลายสิ่ง:
java.lang.NullPointerException
กล่าวคือNullPointerException
เป็นสิ่งผิดปกติในส่วนนี้เนื่องจากไม่ค่อยมีข้อความแสดงข้อผิดพลาดบรรทัดที่สองเป็นสิ่งสำคัญที่สุดในการวินิจฉัย NPE
at Test.main(Test.java:4)
สิ่งนี้บอกเราหลายสิ่ง:
main
วิธีการTest
เรียนหากคุณนับบรรทัดในไฟล์ด้านบนบรรทัด 4 คือบรรทัดที่ฉันติดป้ายกำกับด้วยความคิดเห็น "ที่นี่"
โปรดทราบว่าในตัวอย่างที่ซับซ้อนมากขึ้นจะมีบรรทัดจำนวนมากในการติดตามสแต็ก NPE แต่คุณสามารถมั่นใจได้ว่าบรรทัดที่สอง (บรรทัดแรก "ที่") จะบอกคุณว่า NPE ถูกส่งไปที่ไหน1
กล่าวโดยย่อการติดตามสแต็กจะบอกให้เราทราบอย่างชัดเจนว่าคำสั่งใดของโปรแกรมที่ส่ง NPE ไป
1 - ไม่จริงเลย มีสิ่งที่เรียกว่าข้อยกเว้นซ้อนอยู่ ...
นี่คือส่วนที่ยาก คำตอบสั้น ๆ คือการใช้การอนุมานแบบลอจิคัลกับหลักฐานที่จัดทำโดยการติดตามสแต็คซอร์สโค้ดและเอกสารประกอบ API ที่เกี่ยวข้อง
ลองมาอธิบายด้วยตัวอย่างง่ายๆ (ด้านบน) ก่อน เราเริ่มต้นด้วยการดูบรรทัดที่การติดตามสแต็กได้บอกกับเราว่าเป็นที่ที่ NPE เกิดขึ้น:
int length = foo.length(); // HERE
มันจะโยน NPE ได้อย่างไร?
ในความเป็นจริงมีเพียงวิธีหนึ่งที่มันสามารถเกิดขึ้นได้ถ้ามีค่าfoo
null
จากนั้นเราพยายามเรียกใช้length()
วิธีการnull
และ ... BANG!
แต่ (ฉันได้ยินคุณพูด) จะเกิดอะไรขึ้นถ้า NPE ถูกโยนลงไปในlength()
การเรียกเมธอด?
หากเกิดเหตุการณ์นี้ขึ้นการติดตามสแต็กจะดูแตกต่างกัน บรรทัด "at" บรรทัดแรกจะบอกว่ามีข้อยกเว้นเกิดขึ้นในบางบรรทัดในjava.lang.String
คลาสและบรรทัด 4 ของTest.java
จะเป็นบรรทัด "at" ที่สอง
แล้วมันnull
มาจากไหน? ในกรณีนี้มันชัดเจนและเป็นสิ่งที่เราต้องทำเพื่อแก้ไข (กำหนดค่าที่ไม่ใช่ค่า null ให้กับfoo
)
ตกลงดังนั้นลองทำตัวอย่างที่ซับซ้อนกว่านี้เล็กน้อย นี้จะต้องมีการหักตรรกะ
public class Test {
private static String[] foo = new String[2];
private static int test(String[] bar, int pos) {
return bar[pos].length();
}
public static void main(String[] args) {
int length = test(foo, 1);
}
}
$ javac Test.java
$ java Test
Exception in thread "main" java.lang.NullPointerException
at Test.test(Test.java:6)
at Test.main(Test.java:10)
$
ดังนั้นตอนนี้เรามีสองบรรทัด "ที่" คนแรกสำหรับบรรทัดนี้:
return args[pos].length();
และอันที่สองสำหรับบรรทัดนี้:
int length = test(foo, 1);
ดูที่บรรทัดแรกมันจะโยน NPE ได้อย่างไร มีสองวิธี:
bar
เป็นnull
แล้วbar[pos]
จะโยน NPEbar[pos]
ถูกnull
แล้วโทรlength()
ที่มันจะโยน NPEต่อไปเราต้องทราบว่าสถานการณ์ใดอธิบายถึงสิ่งที่เกิดขึ้นจริง เราจะเริ่มต้นด้วยการสำรวจสิ่งแรก:
ในกรณีที่ไม่bar
มาจากไหน? มันเป็นพารามิเตอร์ของtest
การเรียกเมธอดและถ้าเราดูว่าtest
ถูกเรียกมาอย่างไรเราจะเห็นว่ามันมาจากfoo
ตัวแปรคงที่ นอกจากนี้เราสามารถเห็นได้อย่างชัดเจนว่าเราเริ่มต้นfoo
เป็นค่าที่ไม่เป็นโมฆะ นั่นเพียงพอที่จะยกเลิกคำอธิบายนี้อย่างไม่แน่นอน (ตามทฤษฎีแล้วบางอย่างอาจเปลี่ยน foo
เป็นnull
... แต่นั่นไม่ได้เกิดขึ้นที่นี่)
แล้วสถานการณ์ที่สองของเราล่ะ ทีนี้, เราเห็นได้ว่านั่นpos
คือ1
, นั่นหมายความว่าfoo[1]
ต้องเป็นnull
เช่นนั้น เป็นไปได้ไหม
แน่นอนมันเป็น! และนั่นคือปัญหา เมื่อเราเริ่มต้นเช่นนี้:
private static String[] foo = new String[2];
เราจัดสรร a String[]
ด้วยสององค์ประกอบที่เริ่มต้นnull
ได้ หลังจากนั้นเรายังไม่ได้เปลี่ยนเนื้อหาของfoo
... ดังนั้นจะยังคงเป็นfoo[1]
null
null
มันก็เหมือนกับการที่คุณกำลังพยายามที่จะเข้าถึงวัตถุซึ่งเป็น ลองพิจารณาตัวอย่างด้านล่าง:
TypeA objA;
ในเวลานี้คุณได้เพียงแค่ประกาศวัตถุนี้ แต่ไม่เริ่มต้นหรืออินสแตนซ์ และเมื่อใดก็ตามที่คุณพยายามเข้าถึงทรัพย์สินหรือวิธีการใด ๆ มันจะ NullPointerException
ทำให้เกิดความรู้สึก
ดูตัวอย่างด้านล่างนี้เช่นกัน:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
ข้อยกเว้นตัวชี้ null ถูกส่งออกมาเมื่อแอปพลิเคชันพยายามใช้ null ในกรณีที่จำเป็นต้องใช้วัตถุ เหล่านี้รวมถึง:
null
วัตถุnull
วัตถุnull
ราวกับว่ามันเป็นอาร์เรย์null
ราวกับว่ามันเป็นอาร์เรย์null
ราวกับว่ามันเป็นค่า Throwableแอปพลิเคชันควรโยนอินสแตนซ์ของคลาสนี้เพื่อบ่งชี้การใช้งานnull
วัตถุอย่างผิดกฎหมาย
การอ้างอิง: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
null
เป็นเป้าหมายของการเป็นsynchronized
บล็อก 2) ใช้null
เป็นเป้าหมายของการให้และการแกะกล่องswitch
null
null
ชี้เป็นหนึ่งในจุดที่ไม่มีที่ไหนเลย เมื่อคุณอ้างถึงตัวชี้p
คุณจะพูดว่า "ให้ข้อมูลที่ตำแหน่งที่เก็บไว้ใน" p "ให้ฉันเมื่อp
เป็นnull
ตัวชี้ตำแหน่งที่จัดเก็บในp
คือnowhere
คุณกำลังพูดว่า" ให้ข้อมูลที่ตำแหน่ง 'ไม่มีที่ไหนเลย' " null pointer exception
เห็นได้ชัดว่ามันไม่สามารถทำเช่นนี้จึงพ่น
โดยทั่วไปเป็นเพราะบางสิ่งไม่ได้เริ่มต้นอย่างถูกต้อง
NULL
เขียนเป็นภาษาnull
จาวา และมันเป็นเรื่องที่อ่อนไหว
จำนวนมากของคำอธิบายที่มีอยู่แล้วที่จะอธิบายว่ามันเกิดขึ้นและวิธีการที่จะแก้ไขได้ แต่คุณยังควรปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดที่จะหลีกเลี่ยงNullPointerException
s ที่ทั้งหมด
ดูเพิ่มเติม: รายการปฏิบัติที่ดีที่สุด
ฉันจะเพิ่มสิ่งที่สำคัญมากใช้ประโยชน์จากfinal
ตัวปรับแต่ง
การใช้ตัวดัดแปลง "final" เมื่อใดก็ตามที่เกี่ยวข้องใน Java
สรุป:
final
ฟายเออร์เพื่อบังคับใช้การเริ่มต้นที่ดี@NotNull
และ@Nullable
if("knownObject".equals(unknownObject)
valueOf()
toString()
StringUtils
StringUtils.isEmpty(null)
@Nullable
ตามที่ระบุไว้ด้านบน) และเตือนเกี่ยวกับข้อผิดพลาดที่อาจเกิดขึ้น นอกจากนี้ยังเป็นไปได้ที่จะอนุมานและสร้างคำอธิบายประกอบดังกล่าว (เช่น IntelliJ สามารถทำได้) ขึ้นอยู่กับโครงสร้างรหัสที่มีอยู่
if (obj==null)
หากใช้เป็นโมฆะคุณควรเขียนโค้ดเพื่อจัดการกับสิ่งนั้นด้วย
ใน Java ทุกอย่าง (ไม่รวมประเภทดั้งเดิม) อยู่ในรูปแบบของคลาส
หากคุณต้องการใช้วัตถุใด ๆ คุณมีสองขั้นตอนดังนี้
ตัวอย่าง:
Object object;
object = new Object();
เหมือนกันสำหรับแนวคิดอาร์เรย์:
Item item[] = new Item[5];
item[0] = new Item();
หากคุณไม่ได้ให้ส่วนเริ่มต้นแล้วNullPointerException
เกิดขึ้น
ข้อยกเว้นตัวชี้โมฆะคือตัวบ่งชี้ที่คุณกำลังใช้วัตถุโดยไม่เริ่มต้น
ตัวอย่างเช่นด้านล่างเป็นชั้นเรียนของนักเรียนซึ่งจะใช้ในรหัสของเรา
public class Student {
private int id;
public int getId() {
return this.id;
}
public setId(int newId) {
this.id = newId;
}
}
รหัสด้านล่างให้ข้อยกเว้นตัวชี้โมฆะ
public class School {
Student student;
public School() {
try {
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
เพราะคุณใช้student
แต่คุณลืมที่จะเริ่มต้นมันเหมือนในรหัสที่ถูกต้องที่แสดงด้านล่าง:
public class School {
Student student;
public School() {
try {
student = new Student();
student.setId(12);
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
ในJavaตัวแปรทั้งหมดที่คุณประกาศเป็นจริง "อ้างอิง" ไปยังวัตถุ (หรือดั้งเดิม) และไม่ใช่วัตถุเอง
เมื่อคุณพยายามที่จะดำเนินการวิธีการหนึ่งวัตถุการอ้างอิงขอให้วัตถุที่มีชีวิตในการดำเนินการวิธีการนั้น แต่ถ้าการอ้างอิงคือการอ้างอิง NULL (ไม่มีอะไร, เป็นศูนย์, เป็นโมฆะ, นาดะ) จากนั้นก็ไม่มีทางที่วิธีการได้รับการดำเนินการ จากนั้นรันไทม์แจ้งให้คุณทราบโดยการโยน NullPointerException
การอ้างอิงของคุณคือ "การชี้" เป็นโมฆะดังนั้นจึงเป็น "Null -> Pointer"
วัตถุอาศัยอยู่ในพื้นที่หน่วยความจำ VM และวิธีเดียวในการเข้าถึงโดยใช้this
การอ้างอิง นำตัวอย่างนี้:
public class Some {
private int id;
public int getId(){
return this.id;
}
public setId( int newId ) {
this.id = newId;
}
}
และที่อื่นในรหัสของคุณ:
Some reference = new Some(); // Point to a new object of type Some()
Some otherReference = null; // Initiallly this points to NULL
reference.setId( 1 ); // Execute setId method, now private var id is 1
System.out.println( reference.getId() ); // Prints 1 to the console
otherReference = reference // Now they both point to the only object.
reference = null; // "reference" now point to null.
// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );
// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...
สิ่งนี้เป็นสิ่งสำคัญที่ต้องรู้ - เมื่อไม่มีการอ้างอิงถึงวัตถุอีกต่อไป (ในตัวอย่างด้านบนเมื่อreference
และotherReference
ทั้งคู่ชี้ไปที่โมฆะ) ดังนั้นวัตถุนั้น "ไม่สามารถเข้าถึงได้" ไม่มีทางที่เราจะสามารถทำงานกับมันได้ดังนั้นวัตถุนี้พร้อมที่จะรวบรวมขยะและในบางจุด VM จะเพิ่มหน่วยความจำที่ใช้โดยวัตถุนี้และจะจัดสรรอีก
อีกเหตุการณ์หนึ่งที่เกิดNullPointerException
ขึ้นเมื่อมีการประกาศอาร์เรย์ของวัตถุจากนั้นพยายามที่จะตรวจสอบองค์ประกอบภายในของมันทันที
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
NPE เฉพาะนี้สามารถหลีกเลี่ยงได้หากมีการกลับคำสั่งเปรียบเทียบ กล่าวคือใช้.equals
กับวัตถุที่ไม่เป็นโมฆะที่รับประกันได้
องค์ประกอบทั้งหมดภายในอาร์เรย์จะเริ่มต้นได้ที่ค่าเริ่มต้นของพวกเขาร่วมกัน ; สำหรับประเภทของอาร์เรย์วัตถุใด ๆ null
นั่นหมายความว่าองค์ประกอบทั้งหมดที่มี
คุณต้องเริ่มต้นองค์ประกอบในอาร์เรย์ก่อนที่จะเข้าถึงหรือยกเลิกการลงทะเบียนพวกเขา
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Optional
จะกลับเป็นโมฆะ คำหลักใช้ได้ดี การรู้วิธีป้องกันมันเป็นสิ่งสำคัญ สิ่งนี้เสนอเหตุการณ์ที่เกิดขึ้นทั่วไปอย่างหนึ่งและวิธีการบรรเทา