เหตุใด int num = Integer.getInteger (“ 123”) จึงโยน NullPointerException


106

รหัสต่อไปนี้พ่นNullPointerException:

int num = Integer.getInteger("123");

คอมไพเลอร์ของฉันเรียกใช้getIntegernull เนื่องจากเป็นแบบคงที่หรือไม่ นั่นไม่สมเหตุสมผลเลย!

เกิดอะไรขึ้น?


3
ใช้ Integer.getValue () แทน บล็อกโพสต์นี้เป็นคำอธิบายที่ดีว่าทำไม: konigsberg.blogspot.in/2008/04/…
Pranaysharma

คำตอบ:


212

ภาพใหญ่

มีสองประเด็นในการเล่นที่นี่:

  • Integer getInteger(String) ไม่ได้ทำในสิ่งที่คุณคิด
    • มันกลับมาnullในกรณีนี้
  • การกำหนดจากIntegerถึงintทำให้เกิดการแกะกล่องอัตโนมัติ
    • เนื่องจากIntegerมีnull, NullPointerExceptionโยน

ที่จะแยก(String) "123"ไปคุณสามารถใช้เช่น(int) 123int Integer.parseInt(String)

อ้างอิง

Integer การอ้างอิง API


บน Integer.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ได้ สุดท้ายเมื่อโปรแกรมของคุณใส่ค่าดั้งเดิมอาจส่งผลให้เกิดการสร้างวัตถุที่มีราคาแพงและไม่จำเป็น

มีหลายสถานที่ที่คุณไม่มีทางเลือกอื่นนอกจากการใช้ยาดั้งเดิมชนิดบรรจุกล่องเช่นยาชื่อสามัญ แต่อย่างอื่นคุณควรพิจารณาอย่างจริงจังว่าการตัดสินใจใช้ยาดั้งเดิมชนิดบรรจุกล่องนั้นสมเหตุสมผลหรือไม่

คำถามที่เกี่ยวข้อง


11
ดังนั้นจึงInteger.getInteger(s)เทียบเท่ากับInteger.parseInt(System.getProperty(s))? ฉันคิดว่าฉันชอบอันที่สองแม้ว่ามันจะละเอียดกว่าเพราะมันเน้นความจริงที่ว่าคุณกำลังดึงข้อมูลจากคุณสมบัติของระบบ
MatrixFrog

5
ทันทีที่ฉันโพสต์ความคิดเห็นนั้นฉันก็รู้ว่าฉันสามารถดูที่มาที่แท้จริงของคลาส Integer ได้! ฉันมาถูกทางแล้วยกเว้นว่าจะใช้Integer.decodeแทนInteger.parseIntซึ่งมองหาเลขนำหน้า0xหรือ0เพื่อแยกวิเคราะห์ตัวเลขเป็นเลขฐานสิบหกหรือฐานแปดตามลำดับ
MatrixFrog

สำหรับผู้ที่ถามว่าทำไมNullPointerException? : programmers.stackexchange.com/questions/158908/…
ROMANIA_engineer

2
@Oracle คุณสามารถเลิกใช้ java.lang.Integer.getInteger (String) ได้ไหม
mjaggard


6

กรุณาตรวจสอบเอกสารของวิธีการgetInteger () ในวิธีนี้Stringพารามิเตอร์คือคุณสมบัติของระบบที่กำหนดค่าจำนวนเต็มของคุณสมบัติระบบด้วยชื่อที่ระบุ "123" ไม่ได้เป็นชื่อของสถานที่ให้บริการระบบใด ๆ ตามที่กล่าวไว้ที่นี่ หากคุณต้องการแปลงสตริงนี้ให้intใช้วิธีการเป็น int num = Integer.parseInt("123").

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.