วิธีใช้ null ในสวิตช์


202
Integer i = ...

switch (i){
    case null:
        doSomething0();
        break;    
    }

ในรหัสข้างต้นฉันไม่สามารถใช้ null ในงบกรณีสวิตช์ ฉันจะทำสิ่งนี้ต่างออกไปได้อย่างไร ฉันไม่สามารถใช้defaultเพราะแล้วฉันต้องการทำอย่างอื่น


9
ก่อนที่สวิตช์จะตรวจสอบเงื่อนไขว่างถ้า (i == null) {// dosomething}
Nagaraju Badaeni

8
นี่จะทำให้สวิตช์มีประโยชน์ รูปแบบการจับคู่ภาษาอื่น ๆ ใช้วิธีนี้
Pyrolistical

คำตอบ:


277

ไม่สามารถใช้switchคำสั่งใน Java ได้ ตรวจสอบnullก่อนswitch:

if (i == null) {
    doSomething0();
} else {
    switch (i) {
    case 1:
        // ...
        break;
    }
}

คุณไม่สามารถใช้วัตถุพลการในswitchงบ* เหตุผลที่คอมไพเลอร์ไม่ได้บ่นเกี่ยวกับการswitch (i)ที่iเป็นIntegerเป็นเพราะ Java อัตโนมัติ unboxes ไปยังInteger intในฐานะที่เป็น assylias แล้วกล่าวว่า unboxing จะโยนNullPointerExceptionเมื่อเป็นinull

*ตั้งแต่ Java 7 คุณสามารถใช้Stringในswitchข้อความสั่ง

ข้อมูลเพิ่มเติมเกี่ยวกับswitch(รวมถึงตัวอย่างที่มีตัวแปร null) ในOracle Docs - Switch


16
คุณยังสามารถใช้ enums ในงบ switch
joriki

27
มันสมเหตุสมผลแล้วที่คุณไม่สามารถใช้ null Integer หรือคลาส Wrapper อื่น ๆ ได้เนื่องจากการ unboxing แต่สิ่งที่เกี่ยวกับ enums และสตริง? ทำไมพวกมันถึงเป็นโมฆะไม่ได้?
Luan Nico

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

3
@Realius คุณไม่จำเป็นต้องทำการตรวจสอบ null เสมอไป หากคุณเคารพสัญญารหัสที่คุณให้ไว้กับวิธีการของคุณคุณเกือบจะสามารถจัดการไม่ให้รหัสของคุณยุ่งเหยิงด้วยการตรวจสอบ null แม้ว่าการใช้การยืนยันนั้นดีเสมอ
Joffrey

ฉันต้องการทราบคำตอบสำหรับข้อความค้นหาของ @ LuanNico ด้วย ดูเหมือนว่าไม่มีเหตุผลที่nullไม่สามารถเป็นกรณีที่ถูกต้องเมื่อทำงานกับStringและenumประเภท บางทีenumการนำไปปฏิบัตินั้นอาศัยการโทรหาordinal()เบื้องหลัง (แม้ว่าจะเป็นเช่นนั้นทำไมไม่ถือว่าnullเป็น 'อันดับ' ของ -1?) และStringรุ่นนี้ใช้บางสิ่งบางอย่างโดยใช้intern()และการเปรียบเทียบตัวชี้ (หรืออาศัยบางสิ่งบางอย่าง วัตถุ)?
aroth


40

switch(i)จะโยน NullPointerException ถ้าฉันเป็นnullเพราะมันจะพยายามที่จะ unbox เป็นInteger intดังนั้นcase nullสิ่งที่ผิดกฎหมายก็จะไม่เกิดขึ้น

คุณต้องตรวจสอบว่าฉันไม่ได้เป็นโมฆะก่อนswitchคำสั่ง


23

เอกสาร Java ระบุไว้อย่างชัดเจนว่า:

ข้อห้ามในการใช้ null เป็นฉลากสวิตช์ป้องกันหนึ่งจากการเขียนรหัสที่ไม่สามารถดำเนินการได้ หากการแสดงออกของสวิทช์เป็นประเภทอ้างอิงเช่นชนิดดั้งเดิมแบบกล่องหรือ enum ข้อผิดพลาดรันไทม์จะเกิดขึ้นหากการแสดงออกประเมินเป็นโมฆะในเวลาทำงาน

คุณจะต้องตรวจสอบความถูกต้องของโมฆะก่อนที่จะดำเนินการคำสั่ง Swithch

if (i == null)

ดูคำสั่งเปลี่ยน

case null: // will never be executed, therefore disallowed.

1
javadocs ที่ลิงก์ของคุณไม่ได้พูดว่า "ข้อห้ามในการใช้ null เป็นป้ายกำกับสวิตช์ [ฯลฯ ]"
Patrick M


14

ได้รับ:

public enum PersonType {
    COOL_GUY(1),
    JERK(2);

    private final int typeId;
    private PersonType(int typeId) {
        this.typeId = typeId;
    }

    public final int getTypeId() {
        return typeId;
    }

    public static PersonType findByTypeId(int typeId) {
        for (PersonType type : values()) {
            if (type.typeId == typeId) {
                return type;
            }
        }
        return null;
    }
}

สำหรับฉันแล้วโดยทั่วไปจะจัดแนวกับตารางค้นหาในฐานข้อมูล (สำหรับตารางที่ไม่ค่อยมีการปรับปรุงเท่านั้น)

อย่างไรก็ตามเมื่อฉันพยายามที่จะใช้findByTypeIdในคำสั่งเปลี่ยน (จากส่วนใหญ่ผู้ใช้ใส่) ...

int userInput = 3;
PersonType personType = PersonType.findByTypeId(userInput);
switch(personType) {
case COOL_GUY:
    // Do things only a cool guy would do.
    break;
case JERK:
    // Push back. Don't enable him.
    break;
default:
    // I don't know or care what to do with this mess.
}

... เป็นคนอื่นได้รับรู้ผลการนี้ในการ NPE switch(personType) {@ หนึ่งในการแก้ไข (เช่น "วิธีแก้ปัญหา") ที่ฉันเริ่มใช้คือการเพิ่มUNKNOWN(-1)ประเภท

public enum PersonType {
    UNKNOWN(-1),
    COOL_GUY(1),
    JERK(2);
    ...
    public static PersonType findByTypeId(int id) {
        ...
        return UNKNOWN;
    }
}

ตอนนี้คุณไม่จำเป็นต้องตรวจสอบค่าว่างในตำแหน่งใดและคุณสามารถเลือกหรือไม่จัดการUNKNOWNประเภทได้ (หมายเหตุ: -1เป็นตัวบ่งชี้ที่ไม่น่าเป็นไปได้ในสถานการณ์ทางธุรกิจ แต่เลือกสิ่งที่เหมาะสมกับการใช้งานของคุณ)


2
UNKNOWNเป็นทางออกที่ดีที่สุดในเรื่องนี้ฉันเคยเห็นและเอาชนะ nullchecks
membersound


4

บางไลบรารีพยายามเสนอทางเลือกให้กับswitchคำสั่งbuiltin java Vavrเป็นหนึ่งในนั้นพวกเขาพูดคุยกับมันเพื่อจับคู่รูปแบบ

นี่คือตัวอย่างจากเอกสารประกอบ :

String s = Match(i).of(
    Case($(1), "one"),
    Case($(2), "two"),
    Case($(), "?")
);

คุณสามารถใช้เพรดิเคตใด ๆ แต่พวกเขาเสนอให้พวกเขาหลายคนออกจากกล่องและ$(null)ถูกต้องตามกฎหมายอย่างสมบูรณ์ ฉันพบว่านี่เป็นทางออกที่หรูหรากว่าทางเลือกอื่น แต่ต้องใช้ java8 และการพึ่งพา vavr ไลบรารี่ ...




0

คุณทำไม่ได้ คุณสามารถใช้แบบดั้งเดิม (int, char, short, byte) และ String (Strings ใน java 7 เท่านั้น) ในสวิตช์ primitives ต้องไม่เป็นค่าว่าง
ตรวจสอบiในสภาพที่แยกต่างหากก่อนที่จะเปลี่ยน


4
คุณสามารถใช้ enums ได้เช่นกัน
Karu

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

1
@ LeonardoKenji ประโยคเริ่มต้นไม่มีส่วนเกี่ยวข้องกับ null เลย สิ่งที่คุณกำลังเปิดอยู่จะถูกยกเลิกการลงทะเบียนเพื่อตรวจสอบกรณีอื่น ๆ ดังนั้นประโยคเริ่มต้นจะไม่จัดการกับกรณีที่เป็นโมฆะ (NullPointerException ถูกโยนทิ้งไปก่อนที่มันจะมีโอกาส)
Ben

2
ฉันคิดว่าเขาหมายถึงประโยคเริ่มต้นควรจัดการ null เป็นค่า enum ที่เป็นไปได้อื่น ๆ ที่ไม่ได้ถูกจับโดยกรณีก่อนหน้า
Leo

0

เพียงแค่พิจารณาว่าสวิตช์อาจทำงานได้อย่างไร

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

0

ตามคำตอบ @tetsuo ด้วย java 8:

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.