สำหรับโปรแกรมเมอร์ Java ค่าว่างถือเป็นเรื่องน่าปวดหัว คุณมักถูกคุกคามโดย Null Pointer Exceptions (NPE) แม้แต่นักประดิษฐ์ Java ก็ยอมรับว่านี่เป็นความผิดพลาดครั้งใหญ่ในส่วนของเขา เหตุใด Java จึงไม่เป็นโมฆะ ค่า Null มีมาระยะหนึ่งแล้ว และฉันคิดว่านักประดิษฐ์ Java รู้ว่าค่า Null ทำให้เกิดปัญหามากกว่าปัญหาที่ได้รับการแก้ไข แต่ค่า Null ยังคงอยู่กับ Java
ฉันประหลาดใจมากขึ้นเรื่อยๆ เพราะหลักการออกแบบของ Java คือการทำให้สิ่งต่าง ๆ ง่ายขึ้น นั่นคือเหตุผลว่าทำไมจึงไม่เสียเวลากับพอยน์เตอร์ การโอเวอร์โหลดของโอเปอเรเตอร์ และการนำค่า Null ไปใช้เป็นสิ่งที่ตรงกันข้าม ฉันไม่รู้คำตอบสำหรับคำถามนี้จริงๆ สิ่งที่ฉันรู้ก็คือไม่ว่านักพัฒนา Java และชุมชนโอเพ่นซอร์สจะวิพากษ์วิจารณ์ว่า null แค่ไหน เราก็ต้องอยู่ร่วมกับ null แทนที่จะเสียใจกับการมีอยู่ของ null เราควรเรียนรู้เกี่ยวกับ null ให้ดีขึ้น และให้แน่ใจว่ามีการใช้ null อย่างถูกต้อง
ทำไมคุณต้องเรียนรู้ null ใน Java? เพราะถ้าคุณไม่ใส่ใจกับค่าว่าง Java จะทำให้คุณประสบปัญหา NullPointerException และคุณจะได้เรียนรู้บทเรียนที่เจ็บปวด การเขียนโปรแกรมที่กระตือรือร้นเป็นศิลปะที่ทีม ลูกค้า และผู้ใช้ของคุณจะได้ชื่นชมมากขึ้น จากประสบการณ์ของผม สาเหตุหลักประการหนึ่งสำหรับข้อยกเว้นของตัวชี้ null คือความรู้เกี่ยวกับ null ใน Java ไม่เพียงพอ หลายท่านคงคุ้นเคยกับ null อยู่แล้ว แต่สำหรับผู้ที่ไม่คุ้นเคย คุณสามารถเรียนรู้สิ่งเก่าและใหม่เกี่ยวกับ null ได้ มาเรียนรู้ความรู้ที่สำคัญเกี่ยวกับ null ใน Java อีกครั้ง
Null ใน Java คืออะไร?
อย่างที่บอกไปแล้วว่า null เป็นแนวคิดที่สำคัญมากใน Java ความตั้งใจดั้งเดิมของ null คือเพื่อแสดงถึงสิ่งที่ขาดหายไป เช่น ผู้ใช้ที่หายไป ทรัพยากร หรือสิ่งอื่น ๆ อย่างไรก็ตาม หนึ่งปีต่อมา ข้อยกเว้นตัวชี้ null ที่เป็นปัญหาทำให้โปรแกรมเมอร์ Java คุกคามอย่างมาก ในเนื้อหานี้ เราจะเรียนรู้รายละเอียดพื้นฐานของคีย์เวิร์ด null ใน Java และสำรวจเทคนิคบางอย่างเพื่อลดการตรวจสอบ null ให้เหลือน้อยที่สุด และวิธีหลีกเลี่ยงข้อยกเว้นตัวชี้ null ที่น่ารังเกียจ
1) ก่อนอื่น null คือคีย์เวิร์ดใน Java เช่น public, static และ Final คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ คุณไม่สามารถเขียนค่าว่างเป็น Null หรือ NULL ได้ คอมไพลเลอร์จะไม่รู้จักและรายงานข้อผิดพลาด
คัดลอกรหัสรหัสดังต่อไปนี้:
วัตถุ obj = NULL; // ไม่ตกลง
วัตถุ obj1 = null //ตกลง
โปรแกรมเมอร์ที่ใช้ภาษาอื่นอาจประสบปัญหานี้ แต่ตอนนี้การใช้ IDE ทำให้ปัญหานี้ไม่สำคัญ ในตอนนี้ เมื่อคุณพิมพ์โค้ด IDE เช่น Eclipse และ Netbeans ก็สามารถแก้ไขข้อผิดพลาดนี้ได้ แต่การใช้เครื่องมืออื่น ๆ เช่น notepad, Vim และ Emacs ปัญหานี้จะทำให้คุณเสียเวลาอันมีค่าของคุณ
2) เช่นเดียวกับค่าเริ่มต้นทุกประเภทที่มีค่าเริ่มต้น ตัวอย่างเช่น ค่าเริ่มต้นของ int คือ 0 ค่าเริ่มต้นของบูลีนจะเป็นเท็จ และ null คือค่าเริ่มต้นของประเภทการอ้างอิงใดๆ ก็ตาม พูดอย่างเคร่งครัด นั่นคือค่าเริ่มต้น ของวัตถุทุกประเภท เช่นเดียวกับที่คุณสร้างตัวแปรบูลีนซึ่งมีค่าเริ่มต้นเป็นเท็จ ตัวแปรอ้างอิงใดๆ ใน Java จะมีค่าว่างเป็นค่าเริ่มต้น สิ่งนี้เป็นจริงสำหรับตัวแปรทั้งหมด เช่น ตัวแปรสมาชิก ตัวแปรโลคัล ตัวแปรอินสแตนซ์ ตัวแปรคงที่ (แต่เมื่อคุณใช้ตัวแปรโลคัลที่ไม่ได้เตรียมใช้งาน คอมไพเลอร์จะเตือนคุณ) เพื่อแสดงให้เห็นถึงข้อเท็จจริงนี้ คุณสามารถสังเกตตัวแปรอ้างอิงนี้ได้โดยการสร้างตัวแปรแล้วพิมพ์ค่าของมัน ดังที่แสดงในโค้ดต่อไปนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
วัตถุคงที่ส่วนตัว myObj;
โมฆะคงที่สาธารณะ main (String args []) {
System.out.println("myObjc : " + myObj);
-
ค่าของ myObjc : null คืออะไร
สิ่งนี้เป็นจริงสำหรับทั้งวัตถุแบบคงที่และไม่คงที่ ดังที่คุณเห็นในที่นี้ ฉันกำหนดให้ myObj เป็นการอ้างอิงแบบคงที่ ดังนั้นฉันจึงสามารถใช้ข้อมูลดังกล่าวในเมธอดหลักได้โดยตรง โปรดทราบว่าวิธีการหลักเป็นวิธีการแบบคงที่และไม่สามารถใช้ตัวแปรที่ไม่คงที่ได้
3) เราต้องการชี้แจงความเข้าใจผิดบางอย่าง Null ไม่ใช่ทั้งวัตถุหรือประเภทใด ๆ มันเป็นเพียงค่าพิเศษ คุณสามารถกำหนดให้กับประเภทการอ้างอิงใดก็ได้
คัดลอกรหัสรหัสดังต่อไปนี้:
String str = null; // null สามารถกำหนดให้กับ String ได้
Integer itr = null; // คุณสามารถกำหนด null ให้กับ Integer ได้เช่นกัน
Double dbl = null; // null สามารถกำหนดให้กับ Double ได้
String myStr = (String) null; // null สามารถพิมพ์เป็น String ได้
Integer myItr = (Integer) null; // สามารถพิมพ์เป็น Integer ได้
Double myDbl = (Double) null; // ใช่ เป็นไปได้ ไม่มีข้อผิดพลาด
คุณจะเห็นว่าการส่งค่า null ไปยังประเภทการอ้างอิงใดๆ เป็นไปได้ในขณะคอมไพล์และรันไทม์ และจะไม่เกิดข้อยกเว้นตัวชี้ null ณ รันไทม์
4) Null สามารถกำหนดให้กับตัวแปรอ้างอิงได้ แต่คุณไม่สามารถกำหนด null ให้กับตัวแปรประเภทพื้นฐานได้ เช่น int, double, float และ boolean หากคุณทำเช่นนั้น คอมไพเลอร์จะส่งข้อผิดพลาดดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
int i = null; // ประเภทไม่ตรงกัน : ไม่สามารถแปลงจาก null เป็น int ได้
short s = null; // ประเภทไม่ตรงกัน : ไม่สามารถแปลงจาก null เป็น short ได้
ไบต์ b = null: // ประเภทไม่ตรงกัน: ไม่สามารถแปลงจาก null เป็นไบต์ได้
double d = null; // ประเภทไม่ตรงกัน: ไม่สามารถแปลงจาก null เป็น double ได้
จำนวนเต็ม itr = null; // ไม่เป็นไร
int j = itr; // ก็ใช้ได้เหมือนกัน แต่ NullPointerException ตอนรันไทม์
อย่างที่คุณเห็น เมื่อคุณกำหนด null ให้กับประเภทดั้งเดิมโดยตรง จะเกิดข้อผิดพลาดในการคอมไพล์ แต่ถ้าคุณกำหนด null ให้กับอ็อบเจ็กต์คลาส wrapper แล้วกำหนดอ็อบเจ็กต์ให้กับประเภทพื้นฐานตามลำดับ คอมไพลเลอร์จะไม่รายงาน แต่คุณจะพบกับข้อยกเว้นของตัวชี้ null ณ รันไทม์ สิ่งนี้เกิดจากการแกะกล่องอัตโนมัติใน Java ซึ่งเราจะเห็นในสัญลักษณ์แสดงหัวข้อย่อยถัดไป
5) คลาส wrapper ใด ๆ ที่มีค่า null จะส่งข้อยกเว้นตัวชี้ null เมื่อ Java แกะกล่องและสร้างประเภทข้อมูลพื้นฐาน โปรแกรมเมอร์บางคนคิดผิดว่า autoboxing จะแปลงค่า null เป็นค่าเริ่มต้นของประเภทพื้นฐานที่เกี่ยวข้อง เช่น 0 สำหรับ int และ false สำหรับประเภทบูลีน แต่นั่นไม่ถูกต้อง ดังที่แสดงด้านล่าง:
คัดลอกรหัสรหัสดังต่อไปนี้:
จำนวนเต็ม iAmNull = null;
int i = iAmNull; // ข้อควรจำ - ไม่มีข้อผิดพลาดในการรวบรวม
แต่เมื่อคุณเรียกใช้ข้อมูลโค้ดข้างต้น คุณจะเห็นบนคอนโซลว่าเธรดหลักส่งข้อยกเว้นตัวชี้ค่าว่าง ข้อผิดพลาดดังกล่าวจำนวนมากเกิดขึ้นเมื่อใช้ค่าคีย์ HashMap และ Integer ข้อผิดพลาดจะปรากฏขึ้นเมื่อคุณเรียกใช้โค้ดต่อไปนี้
คัดลอกรหัสรหัสดังต่อไปนี้:
นำเข้า java.util.HashMap;
นำเข้า java.util.Map;
-
* ตัวอย่างของ Autoboxing และ NullPointerExcpetion
-
* @ผู้เขียน WINDOWS 8
-
การทดสอบชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String args []) พ่น InterruptedException {
หมายเลขแผนที่ AndCount = HashMap ใหม่<>();
หมายเลข int[] = {3, 5, 7,9, 11, 13, 17, 19, 2, 3, 5, 33, 12, 5};
สำหรับ(int i : ตัวเลข){
int นับ = numberAndCount.get(i);
numberAndCount.put(i, count++); // NullPointerException ที่นี่
-
-
-
เอาท์พุท:
คัดลอกรหัสรหัสดังต่อไปนี้:
ข้อยกเว้นในเธรด "main" java.lang.NullPointerException
ที่ Test.main (Test.java:25)
รหัสนี้ดูเรียบง่ายและปราศจากข้อผิดพลาด สิ่งที่คุณทำคือค้นหาจำนวนครั้งที่ตัวเลขปรากฏในอาร์เรย์ ซึ่งเป็นเทคนิคทั่วไปในการค้นหาค่าที่ซ้ำกันในอาร์เรย์ Java นักพัฒนาจะได้รับค่าก่อนหน้าก่อน จากนั้นจึงเพิ่มค่าหนึ่ง และสุดท้ายก็ใส่ค่ากลับเข้าไปในแผนที่ โปรแกรมเมอร์อาจคิดว่าเมื่อเรียกเมธอด put แล้ว boxing อัตโนมัติจะจัดการ boxing ของ int ลงใน Interger แต่เขาลืมไปว่าเมื่อตัวเลขไม่มีค่าการนับ เมธอด get() ของ HashMap จะส่งคืนค่าว่าง และไม่ใช่ 0 เนื่องจากค่าเริ่มต้นของ Integer จะเป็น null ไม่ใช่ 0 Autoboxing จะส่งกลับ NullPointerException เมื่อส่งค่า Null ไปยังตัวแปร int ลองนึกภาพว่าโค้ดนี้อยู่ใน if Nest และไม่ได้ทำงานในสภาพแวดล้อม QA แต่เมื่อคุณวางไว้ในสภาพแวดล้อมการใช้งานจริงแล้ว BOOM :-)
6) หากใช้ตัวแปรประเภทการอ้างอิงที่มีค่า Null การดำเนินการอินสแตนซ์จะส่งคืนค่าเท็จ:
คัดลอกรหัสรหัสดังต่อไปนี้:
จำนวนเต็ม iAmNull = null;
ถ้า (อินสแตนซ์ iAmNull ของจำนวนเต็ม) {
System.out.println("iAmNull เป็นอินสแตนซ์ของจำนวนเต็ม");
}อื่น{
System.out.println("iAmNull ไม่ใช่อินสแตนซ์ของจำนวนเต็ม");
-
เอาท์พุท:
คัดลอกรหัสรหัสดังต่อไปนี้:
ฉัน
AmNull ไม่ใช่ตัวอย่างของจำนวนเต็ม
นี่เป็นคุณลักษณะที่สำคัญมากของการดำเนินการอินสแตนซ์ ทำให้มีประโยชน์สำหรับการตรวจสอบประเภทการส่ง
7) คุณอาจรู้ว่าคุณไม่สามารถเรียกใช้เมธอดที่ไม่คงที่เพื่อใช้ตัวแปรประเภทการอ้างอิงที่มีค่าว่างได้ มันจะส่งข้อยกเว้นตัวชี้ null แต่คุณอาจไม่ทราบว่าคุณสามารถใช้วิธีคงที่เพื่อใช้ตัวแปรประเภทการอ้างอิงที่มีค่าเป็น null เนื่องจากวิธีการแบบคงที่ใช้การรวมแบบคงที่ ข้อยกเว้นของตัวชี้ null จะไม่ถูกส่งออกไป นี่คือตัวอย่าง:
คัดลอกรหัสรหัสดังต่อไปนี้:
การทดสอบชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String args []) {
การทดสอบ myObject = null;
myObject.iAmStaticMethod();
myObject.iAmNonStaticMethod();
-
โมฆะคงที่ส่วนตัว iAmStaticMethod () {
System.out.println("ฉันเป็นวิธีการแบบคงที่ สามารถเรียกได้โดยการอ้างอิงแบบ null");
-
โมฆะส่วนตัว iAmNonStaticMethod () {
System.out.println("ฉันไม่ใช่วิธีคงที่ ไม่ต้องเดทที่จะโทรหาฉันแบบ null");
-
เอาท์พุท:
คัดลอกรหัสรหัสดังต่อไปนี้:
ฉันเป็นวิธีการแบบคงที่ สามารถเรียกได้โดยการอ้างอิงแบบโมฆะ
ข้อยกเว้นในเธรด "main" java.lang.NullPointerException
ที่ Testing.main (Testing.java:11)
8) คุณสามารถส่งค่า null ไปยังเมธอดได้ และเมธอดสามารถรับประเภทการอ้างอิงใดๆ ได้ ตัวอย่างเช่น public void print(Object obj) สามารถเรียก print(null) ได้เช่นนี้ นี่เป็นเรื่องปกติจากมุมมองของการคอมไพล์ แต่ผลลัพธ์ขึ้นอยู่กับวิธีการทั้งหมด วิธีการที่ปลอดภัยแบบ Null เช่นวิธีการพิมพ์ในตัวอย่างนี้ อย่าทิ้ง NullPointerException และเพียงออกอย่างสวยงาม หากตรรกะทางธุรกิจอนุญาต ขอแนะนำให้ใช้วิธีที่ไม่เป็นโมฆะ
9) คุณสามารถใช้การดำเนินการ == หรือ != เพื่อเปรียบเทียบค่า Null ได้ แต่คุณไม่สามารถใช้อัลกอริธึมหรือการดำเนินการทางลอจิคัลอื่น เช่น น้อยกว่าหรือมากกว่า ไม่เหมือนกับ SQL ตรงที่ null==null จะส่งคืนค่าจริงใน Java ดังที่แสดงด้านล่าง:
คัดลอกรหัสรหัสดังต่อไปนี้:
การทดสอบชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String args []) พ่น InterruptedException {
สตริง abc = null;
สตริง cde = null;
ถ้า(abc == cde){
System.out.println("null == null เป็นจริงใน Java");
-
ถ้า(โมฆะ!= โมฆะ){
System.out.println("null != null is false in Java");
-
// ตรวจสอบ null แบบคลาสสิก
ถ้า(abc==null){
//ทำอะไรสักอย่าง
-
// ไม่โอเค เกิดข้อผิดพลาดด้านเวลาคอมไพล์
ถ้า(abc > โมฆะ){
-
-
-
เอาท์พุท:
คัดลอกรหัสรหัสดังต่อไปนี้:
null == null เป็นจริงใน Java
ทั้งหมดนี้เกี่ยวกับ null ใน Java ด้วยประสบการณ์ในการเขียนโปรแกรม Java และการใช้ลูกเล่นง่ายๆ เพื่อหลีกเลี่ยงข้อยกเว้นของตัวชี้ null คุณสามารถทำให้โค้ดของคุณปลอดภัยเป็นโมฆะได้ เนื่องจากค่า null มักถูกใช้เป็นค่าว่างหรือค่าที่ไม่ได้เตรียมใช้งาน จึงเป็นที่มาของความสับสน สำหรับเมธอด สิ่งสำคัญมากคือต้องบันทึกว่าเมธอดทำงานอย่างไรเมื่อใช้ค่า null เป็นพารามิเตอร์ โดยรวมแล้ว จำไว้ว่า null คือค่าเริ่มต้นของตัวแปรประเภทการอ้างอิงใดๆ คุณไม่สามารถใช้การอ้างอิง null เพื่อเรียกเมธอดอินสแตนซ์หรือตัวแปรอินสแตนซ์ใดๆ ใน Java ได้