ข้อยกเว้นตัวชี้ Null ( java.lang.NullPointerException) คืออะไรและทำให้เกิดอะไร
วิธีการ / เครื่องมือใดบ้างที่สามารถใช้เพื่อระบุสาเหตุเพื่อให้คุณหยุดข้อยกเว้นจากสาเหตุที่ทำให้โปรแกรมหยุดการทำงานก่อนเวลาอันควร
ข้อยกเว้นตัวชี้ Null ( java.lang.NullPointerException) คืออะไรและทำให้เกิดอะไร
วิธีการ / เครื่องมือใดบ้างที่สามารถใช้เพื่อระบุสาเหตุเพื่อให้คุณหยุดข้อยกเว้นจากสาเหตุที่ทำให้โปรแกรมหยุดการทำงานก่อนเวลาอันควร
คำตอบ:
เมื่อคุณประกาศตัวแปรอ้างอิง (เช่นวัตถุ) คุณกำลังสร้างตัวชี้ไปยังวัตถุจริงๆ พิจารณารหัสต่อไปนี้ที่คุณประกาศตัวแปรประเภทดั้งเดิมint:
int x;
x = 10;
ในตัวอย่างนี้ตัวแปรxคือintและ Java จะเริ่มต้นให้0กับคุณ เมื่อคุณกำหนดค่าของ10ในบรรทัดที่สองค่าของคุณถูกเขียนลงในหน่วยความจำตำแหน่งที่อ้างถึงโดย10x
แต่เมื่อคุณพยายามที่จะประกาศประเภทอ้างอิงมีบางสิ่งที่แตกต่างเกิดขึ้น ใช้รหัสต่อไปนี้:
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 ผมไม่ได้รับอนุญาตให้แก้ไขคำตอบนี้โดยตรงบางทีผู้เขียนสามารถเพิ่มได้หรือไม่)
NullPointerExceptions เป็นข้อยกเว้นที่เกิดขึ้นเมื่อคุณพยายามใช้การอ้างอิงที่ชี้ไปยังตำแหน่งในหน่วยความจำ (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()วิธีการในการอ้างอิงและนี้จะโยนnullNullPointerException
มีหลายวิธีที่คุณสามารถใช้เป็นค่าที่จะส่งผลให้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จาวา และมันเป็นเรื่องที่อ่อนไหว
จำนวนมากของคำอธิบายที่มีอยู่แล้วที่จะอธิบายว่ามันเกิดขึ้นและวิธีการที่จะแก้ไขได้ แต่คุณยังควรปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดที่จะหลีกเลี่ยงNullPointerExceptions ที่ทั้งหมด
ดูเพิ่มเติม: รายการปฏิบัติที่ดีที่สุด
ฉันจะเพิ่มสิ่งที่สำคัญมากใช้ประโยชน์จากfinalตัวปรับแต่ง
การใช้ตัวดัดแปลง "final" เมื่อใดก็ตามที่เกี่ยวข้องใน Java
สรุป:
finalฟายเออร์เพื่อบังคับใช้การเริ่มต้นที่ดี@NotNullและ@Nullableif("knownObject".equals(unknownObject)valueOf()toString()StringUtilsStringUtils.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จะกลับเป็นโมฆะ คำหลักใช้ได้ดี การรู้วิธีป้องกันมันเป็นสิ่งสำคัญ สิ่งนี้เสนอเหตุการณ์ที่เกิดขึ้นทั่วไปอย่างหนึ่งและวิธีการบรรเทา