ไม่มีข้อยกเว้นขณะที่พิมพ์แคสต์ด้วยค่า null ใน java


227
String x = (String) null;

ทำไมไม่มีข้อยกเว้นในคำชี้แจงนี้

String x = null;
System.out.println(x);

nullมันพิมพ์ แต่.toString()วิธีการควรโยนข้อยกเว้นตัวชี้โมฆะ


คุณกำลังพูดถึงข้อยกเว้นอะไรคอมไพเลอร์?
Sajan Chandran

คำตอบ:


323

คุณสามารถส่งnullไปยังประเภทการอ้างอิงใด ๆ โดยไม่มีข้อยกเว้น

printlnวิธีไม่เคยโยนชี้โมฆะเพราะมันตรวจสอบก่อนว่าวัตถุเป็นโมฆะหรือไม่ หาก null "null"แล้วมันก็พิมพ์สตริง มิฉะนั้นจะเรียกtoStringวิธีการของวัตถุนั้น

การเพิ่มรายละเอียดเพิ่มเติม:วิธีการพิมพ์วิธีการโทรString.valueOf(object)ภายในบนวัตถุอินพุต และในvalueOfวิธีการตรวจสอบนี้จะช่วยหลีกเลี่ยงข้อยกเว้นตัวชี้โมฆะ:

return (obj == null) ? "null" : obj.toString();

สำหรับส่วนที่เหลือของความสับสนของคุณเรียกวิธีการใด ๆ กับวัตถุ null ควรโยนข้อยกเว้นตัวชี้โมฆะถ้าไม่ใช่กรณีพิเศษ


1
@JunedAhsan มีกรณีพิเศษอะไรที่ทำให้ไม่ต้องมี NPE
Holloway

@Trengot ตรวจสอบหนึ่งที่กล่าวถึงในคำตอบของปีเตอร์ด้านล่าง
Juned Ahsan

144

คุณสามารถส่งnullไปอ้างอิงได้ทุกประเภท นอกจากนี้คุณยังสามารถเรียกใช้เมธอดที่จัดการnullกับอาร์กิวเมนต์เช่นSystem.out.println(Object)ทำได้ แต่คุณไม่สามารถอ้างอิงnullค่าและเรียกใช้เมธอดนั้นได้

BTW มีสถานการณ์ที่ยุ่งยากซึ่งปรากฏว่าคุณสามารถเรียกใช้เมธอดสแตติกเกี่ยวกับnullค่า

Thread t = null;
t.yield(); // Calls static method Thread.yield() so this runs fine.

12
ว้าว. ถ้าถามฉันจะแน่ใจ 100% ว่าจะมีข้อยกเว้น กรณีที่ยุ่งยาก
Magnilex

2
@Magnilex: แน่นอน! นี่เป็นคำถามเคล็ดลับการสอบ OCPJP ทั่วไป
ccpizza

3
ไม่ใช่เพราะคอมไพเลอร์ใน bytecode "ปรับ" ให้เหมาะสมt.yield() -> Thread.yeld() หรือไม่ คล้ายกับวิธีการfinal int i = 1; while (i == 1)ปรับให้เหมาะกับwhile(true)
SGal

@SGal จะดียิ่งขึ้นเพราะการเพิ่มประสิทธิภาพที่สองคือ AFAIK ไม่ได้บังคับใช้ในขณะที่ชนิดแรกคือ
Paul Stelian

36

นี่คือโดยการออกแบบ คุณสามารถส่งnullไปอ้างอิงได้ทุกประเภท มิฉะนั้นคุณจะไม่สามารถกำหนดให้กับตัวแปรอ้างอิงได้


ขอบคุณ! หมายเหตุเกี่ยวกับการกำหนดค่า Null ให้กับตัวแปรอ้างอิงนี้มีประโยชน์จริง ๆ !
Max

22

การกำหนดค่า null จำเป็นต้องใช้สำหรับการสร้างต่อไปนี้เมื่อเมธอดถูกโหลดมากเกินไปและหากโมฆะถูกส่งไปยังเมธอดที่โอเวอร์โหลดเหล่านี้คอมไพเลอร์ไม่ทราบวิธีการล้างความคลุมเครือดังนั้นเราจำเป็นต้องพิมพ์ null ในกรณีนี้

class A {
  public void foo(Long l) {
    // do something with l
  }
  public void foo(String s) {
    // do something with s      
  }
}
new A().foo((String)null);
new A().foo((Long)null);

มิฉะนั้นคุณไม่สามารถเรียกวิธีที่คุณต้องการ


ในกรณีส่วนใหญ่หล่อเป็นนัยเช่นString bar = null;ปลดเปลื้องมูลค่าให้กับnull Stringจนถึงตอนนี้ฉันแค่ต้องทิ้งค่า null อย่างชัดเจนในการทดสอบที่มีวิธีการมากเกินไปและฉันต้องการทดสอบพฤติกรรมของมันด้วยอินพุตว่าง ยังดีที่ฉันรู้ว่าฉันกำลังจะเขียนคำตอบที่คล้ายกันก่อนที่ฉันจะพบคุณ
Vlasec

สนุกจริง: l instanceof Longและs instanceof Stringจะกลับมาfalseในกรณีเหล่านี้
อัตติลาตันนี่

7

Println(Object) การใช้งาน String.valueOf()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Print(String) ไม่ตรวจสอบเป็นโมฆะ

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}

5

คำตอบมากมายที่นี่พูดถึงแล้ว

คุณสามารถใช้ค่าอ้างอิงใด ๆ ก็ได้

และ

ถ้าอาร์กิวเมนต์เป็นโมฆะสตริงจะเท่ากับ "null"

ฉันสงสัยว่ามีการระบุไว้ที่ไหนและค้นหาข้อมูลจำเพาะ Java:

การอ้างอิงที่เป็นโมฆะสามารถกำหนดหรือส่งต่อไปยังประเภทการอ้างอิงใด ๆ (§5.2, §5.3, §5.5)

หากการอ้างอิงเป็นโมฆะมันจะถูกแปลงเป็นสตริง "null" (อักขระ ASCII สี่ตัว n, u, l, l)


3

อย่างที่คนอื่นเขียนคุณสามารถทิ้งทุกสิ่งได้ โดยปกติแล้วคุณไม่ต้องการสิ่งนั้นคุณสามารถเขียน:

String nullString = null;

โดยไม่ต้องใส่นักแสดงที่นั่น

แต่มีบางโอกาสที่บรรยากาศแบบนั้นมีเหตุผล:

ก) หากคุณต้องการแน่ใจว่าวิธีการเฉพาะนั้นถูกเรียกเช่น:

void foo(String bar) {  ... }
void foo(Object bar) {  ... }

จากนั้นมันจะสร้างความแตกต่างถ้าคุณพิมพ์

foo((String) null) vs. foo(null)

b) ถ้าคุณตั้งใจจะใช้ IDE เพื่อสร้างรหัส ตัวอย่างเช่นฉันมักจะเขียนการทดสอบหน่วยเช่น:

@Test(expected=NullPointerException.class)
public testCtorWithNullWhatever() {
    new MyClassUnderTest((Whatever) null);
}

ฉันกำลังทำ TDD นี่หมายความว่าคลาส "MyClassUnderTest" อาจยังไม่มีอยู่ โดยการเขียนรหัสนั้นฉันสามารถใช้ IDE ของฉันเพื่อสร้างคลาสใหม่ก่อน และจากนั้นสร้างนวกรรมิกยอมรับ "อะไรก็ตาม" อาร์กิวเมนต์ "ออกจากกล่อง" - IDE สามารถคิดจากการทดสอบของฉันที่นวกรรมิกควรใช้อาร์กิวเมนต์ชนิดใดก็ตาม


2

พิมพ์ :

พิมพ์วัตถุ สตริงที่สร้างโดยเมธอด String.valueOf (Object) ถูกแปลเป็นไบต์

ค่าของ :

ถ้าอาร์กิวเมนต์เป็นโมฆะแล้วสตริงจะเท่ากับ "null"; มิฉะนั้นจะส่งคืนค่าของ obj.toString ()

มันก็ wil กลับสตริงที่มีค่า "null" nullเมื่อวัตถุอยู่


2

วิธีนี้มีประโยชน์มากเมื่อใช้วิธีที่ไม่ชัดเจน ตัวอย่างเช่น: JDialog มีตัวสร้างที่มีลายเซ็นต่อไปนี้:

JDialog(Frame, String, boolean, GraphicsConfiguration)
JDialog(Dialog, String, boolean, GraphicsConfiguration)

ฉันต้องใช้ตัวสร้างนี้เพราะฉันต้องการตั้งค่า GraphicsConfiguration แต่ฉันไม่มี parent สำหรับไดอะล็อกนี้ดังนั้นอาร์กิวเมนต์แรกควรเป็นค่าว่าง การใช้

JDialog(null, String, boolean, Graphicsconfiguration) 

คลุมเครือดังนั้นในกรณีนี้ฉันสามารถ จำกัด การโทรให้แคบลงได้โดยใช้ประเภทใดประเภทหนึ่งที่รองรับ:

JDialog((Frame) null, String, boolean, GraphicsConfiguration)

0

คุณสมบัติภาษานี้สะดวกในสถานการณ์นี้

public String getName() {
  return (String) memberHashMap.get("Name");
}

หาก memberHashMap.get ("ชื่อ") ส่งคืนค่า null คุณยังคงต้องการวิธีการด้านบนเพื่อคืนค่า Null โดยไม่ส่งข้อยกเว้น ไม่ว่าคลาสจะเป็นอะไรก็ตาม null เป็นโมฆะ

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