ฟังก์ชั่นนี้จะถูกเพิ่มเข้าไปในเวอร์ชั่น Java ภายหลังหรือไม่?
บางคนสามารถอธิบายได้ว่าทำไมฉันไม่สามารถทำสิ่งนี้ในขณะที่switchคำสั่งทางเทคนิคของ Java ทำงานได้หรือไม่
"Don't hold your breath."lol, bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179
                ฟังก์ชั่นนี้จะถูกเพิ่มเข้าไปในเวอร์ชั่น Java ภายหลังหรือไม่?
บางคนสามารถอธิบายได้ว่าทำไมฉันไม่สามารถทำสิ่งนี้ในขณะที่switchคำสั่งทางเทคนิคของ Java ทำงานได้หรือไม่
"Don't hold your breath."lol, bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179
                คำตอบ:
คำสั่ง Switch กับStringcase ถูกนำไปใช้ในJava SE 7อย่างน้อย 16 ปีหลังจากที่ถูกร้องขอครั้งแรก ไม่มีเหตุผลที่ชัดเจนสำหรับการหน่วงเวลา แต่มีแนวโน้มว่าจะเกี่ยวกับประสิทธิภาพ
ขณะนี้คุณลักษณะดังกล่าวได้รับการติดตั้งjavac ด้วยกระบวนการ "ยกเลิกการชำระเงิน" ไวยากรณ์ที่สะอาดและมีระดับสูงโดยใช้Stringค่าคงที่ในcaseการประกาศจะถูกขยายในเวลาคอมไพล์เป็นรหัสที่ซับซ้อนมากขึ้นหลังจากรูปแบบ รหัสผลลัพธ์ใช้คำแนะนำ JVM ที่มีอยู่เสมอ
A switchพร้อมStringเคสถูกแปลเป็นสองสวิตช์ระหว่างการคอมไพล์ ครั้งแรกที่จับคู่แต่ละสตริงกับจำนวนเต็มเฉพาะตำแหน่งของมันในสวิตช์เดิม ทำได้โดยการสลับรหัสแฮชของป้ายกำกับก่อน กรณีที่เกี่ยวข้องคือifคำสั่งที่ทดสอบความเท่าเทียมกันของสตริง; ถ้ามีการชนกันบนกัญชา, if-else-ifการทดสอบเป็นซ้อน สวิตช์ที่สองสะท้อนว่าในซอร์สโค้ดต้นฉบับ แต่แทนที่ฉลากเคสด้วยตำแหน่งที่สอดคล้องกัน กระบวนการสองขั้นตอนนี้ทำให้ง่ายต่อการรักษาการควบคุมการไหลของสวิตช์เดิม
สำหรับความลึกด้านเทคนิคเพิ่มเติมswitchคุณสามารถอ้างถึงข้อกำหนด JVM ซึ่งการรวบรวมคำสั่งสวิตช์อธิบายไว้ สรุปมีคำแนะนำ JVM ที่แตกต่างกันสองคำที่สามารถใช้สำหรับสวิตช์ได้ขึ้นอยู่กับความแตกต่างของค่าคงที่ที่ใช้โดยเคส ทั้งสองขึ้นอยู่กับการใช้ค่าคงที่จำนวนเต็มสำหรับแต่ละกรณีเพื่อดำเนินการอย่างมีประสิทธิภาพ
หากค่าคงที่หนาแน่นพวกเขาจะใช้เป็นดัชนี (หลังจากลบค่าต่ำสุด) ลงในตารางของพอยน์เตอร์คำสั่ง - tableswitchคำสั่ง
หากค่าคงที่เบาบางจะทำการค้นหาแบบไบนารีสำหรับกรณีที่ถูกต้องนั่นคือlookupswitchคำสั่ง
ในการกำจัดวัตถุa switchบนStringคำแนะนำทั้งสองมีแนวโน้มที่จะใช้ lookupswitchเหมาะสำหรับสวิทช์ครั้งแรกในรหัสกัญชาเพื่อหาสิ่งที่ตำแหน่งเดิมของคดี tableswitchลำดับส่งผลให้เป็นแบบธรรมชาติสำหรับ
คำแนะนำทั้งสองต้องการค่าคงที่จำนวนเต็มที่กำหนดให้แต่ละกรณีเพื่อจัดเรียงในเวลาคอมไพล์ ที่รันไทม์ในขณะที่O(1)ประสิทธิภาพtableswitchโดยทั่วไปจะดูดีกว่าO(log(n))ประสิทธิภาพของlookupswitchมันก็ต้องมีการวิเคราะห์บางอย่างเพื่อตรวจสอบว่าตารางมีความหนาแน่นเพียงพอที่จะปรับการแลกเปลี่ยนพื้นที่เวลา Bill Venners เขียนบทความที่ยอดเยี่ยมซึ่งครอบคลุมเนื้อหานี้อย่างละเอียดยิ่งขึ้นพร้อมกับการดูคำแนะนำการควบคุมการไหลของ Java อื่น ๆ
ก่อนหน้า JDK 7 enumสามารถประมาณStringสวิตช์ที่ใช้ วิธีนี้ใช้วิธีสแตติกที่valueOfสร้างขึ้นโดยคอมไพเลอร์ในทุกenumประเภท ตัวอย่างเช่น:
Pill p = Pill.valueOf(str);
switch(p) {
  case RED:  pop();  break;
  case BLUE: push(); break;
}Pillเพื่อดำเนินการบางอย่างตามที่strฉันจะยืนยันว่า - อื่นเป็นที่นิยมเพราะมันช่วยให้คุณสามารถจัดการstrค่านอกช่วง RED, BLUE โดยไม่ต้องจับยกเว้นvalueOfหรือตรวจสอบการแข่งขันกับชื่อของตนเอง การแจงนับแต่ละประเภทซึ่งเพิ่งเพิ่มค่าใช้จ่ายที่ไม่จำเป็น จากประสบการณ์ของฉันมันเป็นเพียงความรู้สึกที่จะใช้valueOfในการแปลงเป็นการแจงนับหากจำเป็นต้องมีการแสดงค่า typesype ที่เป็นความลับในภายหลัง
                    (hash >> x) & ((1<<y)-1)จะให้ค่าที่แตกต่างกันสำหรับสตริงทุกอันที่hashCodeแตกต่างกันและ(1<<y)น้อยกว่าสองเท่าของจำนวนสตริง (หรือที่ อย่างน้อยก็ไม่ยิ่งใหญ่ไปกว่านั้น)
                    หากคุณมีสถานที่ในรหัสของคุณที่คุณสามารถเปิดใช้งานสตริงได้ก็ควรจะปรับโครงสร้างสตริงให้ดีขึ้นเพื่อระบุจำนวนของค่าที่เป็นไปได้ซึ่งคุณสามารถเปิดได้ แน่นอนว่าคุณ จำกัด ค่าที่อาจเป็นไปได้ของ Strings ที่คุณสามารถมีได้ในการระบุซึ่งอาจเป็นหรือไม่ต้องการก็ได้
แน่นอนการแจงนับของคุณอาจมีรายการสำหรับ 'อื่น ๆ ' และวิธี fromString (String) จากนั้นคุณอาจมี
ValueEnum enumval = ValueEnum.fromString(myString);
switch (enumval) {
   case MILK: lap(); break;
   case WATER: sip(); break;
   case BEER: quaff(); break;
   case OTHER: 
   default: dance(); break;
}ต่อไปนี้เป็นตัวอย่างที่สมบูรณ์ตามการโพสต์ของ JeeBee โดยใช้ java enum แทนการใช้วิธีการที่กำหนดเอง
โปรดทราบว่าใน Java SE 7 และใหม่กว่าคุณสามารถใช้วัตถุ String ในการแสดงออกของคำสั่งเปลี่ยนแทน
public class Main {
    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) {
      String current = args[0];
      Days currentDay = Days.valueOf(current.toUpperCase());
      switch (currentDay) {
          case MONDAY:
          case TUESDAY:
          case WEDNESDAY:
              System.out.println("boring");
              break;
          case THURSDAY:
              System.out.println("getting better");
          case FRIDAY:
          case SATURDAY:
          case SUNDAY:
              System.out.println("much better");
              break;
      }
  }
  public enum Days {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
  }
}สวิตช์ที่ใช้จำนวนเต็มสามารถปรับให้เหมาะกับโค้ดที่มีประสิทธิภาพมาก สวิทช์ที่ยึดตามชนิดข้อมูลอื่นสามารถรวบรวมได้กับชุดคำสั่ง if () เท่านั้น
ด้วยเหตุนี้ C & C ++ จึงอนุญาตเฉพาะการสลับกับประเภทจำนวนเต็มเนื่องจากไม่มีประโยชน์กับประเภทอื่น ๆ
นักออกแบบของ C # ตัดสินใจว่าสไตล์นั้นสำคัญแม้ว่าจะไม่มีประโยชน์ก็ตาม
ผู้ออกแบบของ Java คิดว่าเหมือนนักออกแบบของ C
ตัวอย่างของการStringใช้โดยตรงตั้งแต่ 1.7 อาจปรากฏขึ้นเช่นกัน:
public static void main(String[] args) {
    switch (args[0]) {
        case "Monday":
        case "Tuesday":
        case "Wednesday":
            System.out.println("boring");
            break;
        case "Thursday":
            System.out.println("getting better");
        case "Friday":
        case "Saturday":
        case "Sunday":
            System.out.println("much better");
            break;
    }
}James Curran พูดอย่างย่อ ๆ ว่า: "สวิตช์ที่ใช้จำนวนเต็มสามารถปรับให้เหมาะกับโค้ดที่มีประสิทธิภาพได้มากสวิตช์ที่ใช้ชนิดข้อมูลอื่นสามารถรวบรวมได้เป็นชุดคำสั่ง if () เท่านั้นด้วยเหตุนี้ C & C ++ อนุญาตเฉพาะสวิตช์ที่เป็นประเภทจำนวนเต็มเท่านั้น เพราะมันไม่มีจุดหมายกับประเภทอื่น "
ความคิดเห็นของฉันและเป็นเพียงสิ่งนั้นคือทันทีที่คุณเริ่มเปลี่ยนสิ่งที่ไม่ใช่ภาษาดั้งเดิมคุณจะต้องเริ่มคิดถึง "เท่ากับ" กับ "==" การเปรียบเทียบสองสตริงแรกอาจเป็นขั้นตอนที่ค่อนข้างยาวซึ่งจะเป็นการเพิ่มปัญหาด้านประสิทธิภาพที่กล่าวถึงข้างต้น ประการที่สองหากมีการสลับกับสตริงจะมีความต้องการสำหรับการสลับบนสตริงโดยไม่สนใจขนาดตัวอักษรสลับกับสตริงพิจารณา / ละเว้นสถานที่การเปลี่ยนสตริงตาม regex .... ฉันจะอนุมัติการตัดสินใจที่ประหยัดเวลามากสำหรับ นักพัฒนาภาษาเสียค่าใช้จ่ายเล็กน้อยสำหรับโปรแกรมเมอร์
matched not matched(ไม่คำนึงถึงสิ่งต่าง ๆ เช่น [ชื่อ] กลุ่ม / อื่น ๆ )
                    นอกเหนือจากข้อโต้แย้งที่ดีข้างต้นฉันจะเพิ่มผู้คนจำนวนมากในวันนี้ที่เห็นswitchว่าเป็นส่วนที่เหลือล้าสมัยของขั้นตอนที่ผ่านมาของ Java (กลับไปที่ครั้ง C)
ฉันไม่ได้แบ่งปันความคิดเห็นนี้อย่างเต็มที่ฉันคิดว่าswitchอาจมีประโยชน์ในบางกรณีอย่างน้อยก็เนื่องจากความเร็วของมันและอย่างไรก็ตามมันก็ยังดีกว่าชุดตัวเลขที่เรียงซ้อนที่else ifฉันเห็นในบางโค้ด ...
แต่จริงๆแล้วมันคุ้มค่าที่จะดูกรณีที่คุณต้องการสวิตช์และดูว่ามันไม่สามารถถูกแทนที่ด้วย OO ที่มากกว่านี้ได้ไหม ตัวอย่างเช่น enums ใน Java 1.5+, บางที HashTable หรือคอลเล็กชันอื่น ๆ (บางครั้งฉันเสียใจที่เราไม่มีฟังก์ชั่น (ไม่ระบุชื่อ) ในฐานะพลเมืองชั้นหนึ่งเช่นใน Lua - ซึ่งไม่มีสวิตช์ - หรือ JavaScript) หรือแม้กระทั่งหลากหลาย
หากคุณไม่ได้ใช้ JDK7 หรือสูงกว่าคุณสามารถใช้hashCode()เพื่อจำลองมันได้ เพราะString.hashCode()มักจะส่งกลับค่าที่แตกต่างกันสำหรับสตริงที่แตกต่างกันและมักจะส่งกลับค่าเท่ากับสตริงเท่ากันมันมีความน่าเชื่อถือเป็นธรรม (สตริงที่แตกต่างกันสามารถผลิตกัญชารหัสเดียวกับ @Lii กล่าวถึงในการแสดงความคิดเห็นเช่น"FB"และ"Ea") ดูเอกสาร
ดังนั้นรหัสจะเป็นดังนี้:
String s = "<Your String>";
switch(s.hashCode()) {
case "Hello".hashCode(): break;
case "Goodbye".hashCode(): break;
}intวิธีการที่คุณจะได้ในทางเทคนิคสลับบน
หรือคุณสามารถใช้รหัสต่อไปนี้:
public final class Switch<T> {
    private final HashMap<T, Runnable> cases = new HashMap<T, Runnable>(0);
    public void addCase(T object, Runnable action) {
        this.cases.put(object, action);
    }
    public void SWITCH(T object) {
        for (T t : this.cases.keySet()) {
            if (object.equals(t)) { // This means that the class works with any object!
                this.cases.get(t).run();
                break;
            }
        }
    }
}caseมีให้ฉันคิดว่าเป็นค่าคงที่เสมอและString.hashCode()ไม่ใช่เช่นนั้น (แม้ว่าในการคำนวณการปฏิบัติไม่เคยเปลี่ยนแปลงระหว่าง JVMs)
                    caseค่าข้อความไม่ต้องถูกกำหนดในเวลารวบรวมเพื่อให้ทำงานได้อย่างประณีต
                    เป็นเวลาหลายปีแล้วที่เราได้ใช้ตัวประมวลผลล่วงหน้า (โอเพ่นซอร์ส) สำหรับเรื่องนี้
//#switch(target)
case "foo": code;
//#endไฟล์ที่ประมวลผลล่วงหน้ามีชื่อว่า Foo.jpp และประมวลผลเป็น Foo.java ด้วยสคริปต์ ant
ข้อดีคือมันถูกประมวลผลเป็น Java ที่รันบน 1.0 (แม้ว่าโดยทั่วไปแล้วเราจะสนับสนุนกลับไปที่ 1.4 เท่านั้น) นอกจากนี้การทำเช่นนี้ (สวิตช์สตริงจำนวนมาก) ทำได้ง่ายกว่าเมื่อเปรียบเทียบกับ fudging ด้วย enums หรือวิธีแก้ไขอื่น ๆ - รหัสนั้นง่ายกว่ามากในการอ่านบำรุงรักษาและเข้าใจ IIRC (ไม่สามารถให้สถิติหรือเหตุผลทางเทคนิค ณ จุดนี้) มันเร็วกว่า Java เทียบเท่าทั่วไป
ข้อเสียคือคุณไม่ได้แก้ไข Java ดังนั้นจึงมีเวิร์กโฟลว์เพิ่มขึ้นเล็กน้อย (แก้ไขประมวลผลคอมไพล์ / ทดสอบ) และ IDE จะเชื่อมโยงกลับไปที่ Java ซึ่งมีความซับซ้อนเล็กน้อย (สวิตช์กลายเป็นชุดของขั้นตอนตรรกะอื่น / ตรรกะ) และลำดับตัวเรือนสวิตช์ไม่ได้รับการปรับปรุง
ฉันไม่แนะนำสำหรับ 1.7+ แต่มีประโยชน์ถ้าคุณต้องการโปรแกรม Java ที่กำหนดเป้าหมาย JVM ก่อนหน้านี้ (เนื่องจาก Joe สาธารณะไม่ค่อยติดตั้งล่าสุด)
คุณจะได้รับจาก SVNหรือเรียกดูออนไลน์รหัส คุณจะต้องEBuildเพื่อสร้างมันตามที่เป็นอยู่
คำตอบอื่น ๆ ได้กล่าวว่าสิ่งนี้ถูกเพิ่มเข้ามาใน Java 7 และให้วิธีแก้ไขปัญหาสำหรับรุ่นก่อนหน้า คำตอบนี้พยายามที่จะตอบว่า "ทำไม"
Java เป็นปฏิกิริยาต่อความซับซ้อนของ C ++ มันถูกออกแบบมาให้เป็นภาษาที่เรียบง่ายสะอาดตา
String มีการจัดการกรณีพิเศษเล็กน้อยในภาษา แต่สำหรับฉันดูเหมือนว่านักออกแบบพยายามที่จะรักษาปริมาณของปลอกพิเศษและน้ำตาล syntactic ให้น้อยที่สุด
การสลับสายค่อนข้างซับซ้อนภายใต้ประทุนเนื่องจากสตริงไม่ใช่ประเภทดั้งเดิม มันไม่ใช่คุณสมบัติทั่วไปในขณะที่ Java ถูกออกแบบและไม่เหมาะกับการออกแบบที่เรียบง่าย โดยเฉพาะอย่างยิ่งเมื่อพวกเขาตัดสินใจที่จะไม่ใช้ตัวพิมพ์เล็ก == สำหรับสตริงมันจะแปลกไปหน่อยสำหรับกรณีที่ == ไม่ทำงาน
ระหว่าง 1.0 ถึง 1.4 ภาษานั้นค่อนข้างคงเดิม การปรับปรุงส่วนใหญ่ของจาวาอยู่ที่ด้านห้องสมุด
ทุกอย่างเปลี่ยนไปด้วย Java 5 ภาษาได้ถูกขยายออกไปอย่างมาก ส่วนขยายเพิ่มเติมตามมาในรุ่น 7 และ 8 ฉันคาดหวังว่าการเปลี่ยนแปลงทัศนคตินี้ได้รับแรงหนุนจากการเพิ่มขึ้นของ C #
JEP 354: สลับนิพจน์ (ดูตัวอย่าง)ใน JDK-13 และ JEP 361: เปลี่ยนนิพจน์ (มาตรฐาน)ใน JDK-14 จะขยายคำสั่ง switchเพื่อให้สามารถใช้เป็นนิพจน์ได้
ตอนนี้คุณสามารถ:
case L ->):
รหัสทางด้านขวาของฉลากสวิตช์ "case L ->" ถูก จำกัด ให้เป็นนิพจน์บล็อกหรือ (เพื่อความสะดวก) คำสั่งส่งข้อความ
เพื่อให้ได้ค่าจากนิพจน์สวิตช์,
breakด้วยคำสั่ง value จะถูกดร็อปไว้ในyieldข้อความสั่ง
ดังนั้นตัวอย่างจากคำตอบ ( 1 , 2 ) อาจมีลักษณะเช่นนี้:
  public static void main(String[] args) {
    switch (args[0]) {
      case "Monday", "Tuesday", "Wednesday" ->  System.out.println("boring");
      case "Thursday" -> System.out.println("getting better");
      case "Friday", "Saturday", "Sunday" -> System.out.println("much better");
    }ไม่สวยมาก แต่นี่เป็นอีกวิธีสำหรับ Java 6 และซอลเบลโลว์:
String runFct = 
        queryType.equals("eq") ? "method1":
        queryType.equals("L_L")? "method2":
        queryType.equals("L_R")? "method3":
        queryType.equals("L_LR")? "method4":
            "method5";
Method m = this.getClass().getMethod(runFct);
m.invoke(this);มันเป็นเรื่องง่ายใน Groovy; ฉันฝัง jar Groovy และสร้างgroovyคลาสยูทิลิตี้เพื่อทำสิ่งเหล่านี้ทั้งหมดและอีกมากมายที่ฉันพบว่าน่ารำคาญใน Java (เนื่องจากฉันติดอยู่กับ Java 6 ในองค์กร)
it.'p'.each{
switch (it.@name.text()){
   case "choclate":
     myholder.myval=(it.text());
     break;
     }}...เมื่อคุณใช้ Intellij ดูที่:
ไฟล์ -> โครงสร้างโครงการ -> โครงการ
ไฟล์ -> โครงสร้างโครงการ -> โมดูล
เมื่อคุณมีหลายโมดูลตรวจสอบให้แน่ใจว่าคุณตั้งค่าระดับภาษาที่ถูกต้องในแท็บโมดูล
public class StringSwitchCase { 
    public static void main(String args[]) {
        visitIsland("Santorini"); 
        visitIsland("Crete"); 
        visitIsland("Paros"); 
    } 
    public static void visitIsland(String island) {
         switch(island) {
          case "Corfu": 
               System.out.println("User wants to visit Corfu");
               break; 
          case "Crete": 
               System.out.println("User wants to visit Crete");
               break; 
          case "Santorini": 
               System.out.println("User wants to visit Santorini");
               break; 
          case "Mykonos": 
               System.out.println("User wants to visit Mykonos");
               break; 
         default: 
               System.out.println("Unknown Island");
               break; 
         } 
    } 
}