รหัสต่อไปนี้พ่นNullPointerException
:
int num = Integer.getInteger("123");
คอมไพเลอร์ของฉันเรียกใช้getInteger
null เนื่องจากเป็นแบบคงที่หรือไม่ นั่นไม่สมเหตุสมผลเลย!
เกิดอะไรขึ้น?
รหัสต่อไปนี้พ่นNullPointerException
:
int num = Integer.getInteger("123");
คอมไพเลอร์ของฉันเรียกใช้getInteger
null เนื่องจากเป็นแบบคงที่หรือไม่ นั่นไม่สมเหตุสมผลเลย!
เกิดอะไรขึ้น?
คำตอบ:
มีสองประเด็นในการเล่นที่นี่:
Integer getInteger(String)
ไม่ได้ทำในสิ่งที่คุณคิด
null
ในกรณีนี้Integer
ถึงint
ทำให้เกิดการแกะกล่องอัตโนมัติ
Integer
มีnull
, NullPointerException
โยนที่จะแยก(String) "123"
ไปคุณสามารถใช้เช่น(int) 123
int Integer.parseInt(String)
Integer
การอ้างอิง APIInteger.getInteger
นี่คือสิ่งที่เอกสารได้กล่าวถึงวิธีการนี้:
public static Integer getInteger(String nm)
: กำหนดค่าจำนวนเต็มของคุณสมบัติระบบด้วยชื่อที่ระบุ หากไม่มีคุณสมบัติที่มีชื่อที่ระบุหากชื่อที่ระบุว่างเปล่าหรือnull
หรือหากคุณสมบัติไม่มีรูปแบบตัวเลขที่ถูกต้องระบบnull
จะส่งคืน
กล่าวอีกนัยหนึ่งวิธีนี้ไม่มีส่วนเกี่ยวข้องกับการแยกวิเคราะห์ a String
ถึงint/Integer
ค่า แต่จะเกี่ยวข้องกับSystem.getProperty
วิธีการ
เป็นที่ยอมรับว่าอาจเป็นเรื่องที่น่าประหลาดใจทีเดียว โชคไม่ดีที่ห้องสมุดมีเรื่องน่าประหลาดใจเช่นนี้ แต่มันสอนบทเรียนอันมีค่าให้คุณ: ค้นหาเอกสารเสมอเพื่อยืนยันว่าวิธีการใดทำอย่างไร
โดยบังเอิญความแตกต่างของปัญหานี้ถูกนำเสนอในReturn of the Puzzlers: Schlock and Awe (TS-5186) , Josh Bloch และงานนำเสนอ JavaOne ของ Neal Gafter ในปี 2009 ของ Neal Gafter นี่คือสไลด์สรุป:
คุณธรรม
- วิธีการที่แปลกและน่ากลัวแฝงตัวอยู่ในห้องสมุด
- บางคนมีชื่อที่ฟังดูไม่เป็นอันตราย
- หากรหัสของคุณทำงานผิดปกติ
- ตรวจสอบให้แน่ใจว่าคุณเรียกใช้วิธีการที่ถูกต้อง
- อ่านเอกสารของไลบรารี
- สำหรับนักออกแบบ API
- อย่าละเมิดหลักการของความประหลาดใจอย่างน้อยที่สุด
- อย่าละเมิดลำดับชั้นที่เป็นนามธรรม
- อย่าใช้ชื่อที่คล้ายกันสำหรับพฤติกรรมที่แตกต่างกันอย่างสิ้นเชิง
เพื่อความสมบูรณ์นอกจากนี้ยังมีวิธีการเหล่านี้ที่คล้ายคลึงกับInteger.getInteger
:
แน่นอนปัญหาอื่น ๆ คือวิธีการNullPointerException
โยน เพื่อมุ่งเน้นไปที่ปัญหานี้เราสามารถลดความซับซ้อนของข้อมูลโค้ดได้ดังนี้:
Integer someInteger = null;
int num = someInteger; // throws NullPointerException!!!
นี่คือคำพูดจาก Effective Java 2nd Edition, Item 49: ชอบประเภทดั้งเดิมกับ primitives แบบบรรจุกล่อง:
โดยสรุปให้ใช้ primitives ตามความต้องการของ primitive แบบกล่องเมื่อใดก็ตามที่คุณมีทางเลือก ประเภทดั้งเดิมนั้นง่ายกว่าและเร็วกว่า หากคุณต้องใช้ผลิตภัณฑ์ดั้งเดิมชนิดบรรจุกล่องโปรดระวัง! Autoboxing ช่วยลดความฟุ่มเฟือย แต่ไม่เป็นอันตรายจากการใช้แบบดั้งเดิมชนิดบรรจุกล่อง เมื่อโปรแกรมของคุณเปรียบเทียบแบบดั้งเดิมสองกล่องกับตัว
==
ดำเนินการจะทำการเปรียบเทียบตัวตนซึ่งแทบจะไม่ใช่สิ่งที่คุณต้องการ เมื่อโปรแกรมของคุณทำการคำนวณแบบผสมที่เกี่ยวข้องกับไพรเมทีฟชนิดบรรจุกล่องและแบบไม่มีกล่องโปรแกรมจะทำการแกะกล่องและเมื่อโปรแกรมของคุณทำการแกะกล่องก็สามารถโยนNullPointerException
ได้ สุดท้ายเมื่อโปรแกรมของคุณใส่ค่าดั้งเดิมอาจส่งผลให้เกิดการสร้างวัตถุที่มีราคาแพงและไม่จำเป็น
มีหลายสถานที่ที่คุณไม่มีทางเลือกอื่นนอกจากการใช้ยาดั้งเดิมชนิดบรรจุกล่องเช่นยาชื่อสามัญ แต่อย่างอื่นคุณควรพิจารณาอย่างจริงจังว่าการตัดสินใจใช้ยาดั้งเดิมชนิดบรรจุกล่องนั้นสมเหตุสมผลหรือไม่
Integer.getInteger(s)
เทียบเท่ากับInteger.parseInt(System.getProperty(s))
? ฉันคิดว่าฉันชอบอันที่สองแม้ว่ามันจะละเอียดกว่าเพราะมันเน้นความจริงที่ว่าคุณกำลังดึงข้อมูลจากคุณสมบัติของระบบ
Integer.decode
แทนInteger.parseInt
ซึ่งมองหาเลขนำหน้า0x
หรือ0
เพื่อแยกวิเคราะห์ตัวเลขเป็นเลขฐานสิบหกหรือฐานแปดตามลำดับ
NullPointerException
? : programmers.stackexchange.com/questions/158908/…
จากhttp://konigsberg.blogspot.com/2008/04/integergetinteger-are-you-kidding-me.html :
getInteger 'กำหนดค่าจำนวนเต็มของคุณสมบัติระบบด้วยชื่อที่ระบุ'
คุณต้องการสิ่งนี้:
Integer.parseInt("123")
กรุณาตรวจสอบเอกสารของวิธีการgetInteger () ในวิธีนี้String
พารามิเตอร์คือคุณสมบัติของระบบที่กำหนดค่าจำนวนเต็มของคุณสมบัติระบบด้วยชื่อที่ระบุ "123" ไม่ได้เป็นชื่อของสถานที่ให้บริการระบบใด ๆ ตามที่กล่าวไว้ที่นี่ หากคุณต้องการแปลงสตริงนี้ให้int
ใช้วิธีการเป็น
int num = Integer.parseInt("123")
.