ประโยชน์ของการสลับใช้ Strings ใน Java 7 คืออะไร


19

เมื่อฉันเริ่มโปรแกรมใน Java ความจริงที่ว่างบ switch ไม่ได้ทำให้สายผิดหวัง จากนั้นในการใช้ Enums ฉันตระหนักถึงประโยชน์ที่คุณได้รับกับพวกเขาแทนที่จะส่งผ่านค่าดิบ - ความปลอดภัยของประเภท

ฉันกำลังดิ้นรนที่จะนึกถึงสถานการณ์ที่มี SE7 ตอนนี้ฉันตัดสินใจที่จะใช้สวิตช์ที่มีสตริงเป็นอินพุตแทนที่จะเป็น Enums หากพวกเขาจะดำเนินการผ่านการเปลี่ยนสตริงทั้งหมด (เช่นมากกว่าการแข่งขันบางส่วนหรือ regex) ก็ดูเหมือนจะไม่ให้เหตุผลน้อยกว่ารหัสที่จะเปลี่ยน

และด้วยเครื่องมือ IDE และอัตราส่วนการอ่าน - เขียนของการเขียนโค้ดฉันจะมีความสุขมากขึ้นในการสร้าง Enum พิเศษโดยอัตโนมัติมากกว่าการส่งผ่านค่าสตริง

พวกเขานำประโยชน์อะไรมาให้เราในฐานะโปรแกรมเมอร์ จานหม้อไอน้ำน้อยลงหรือไม่

ไม่รู้สึกว่าภาษากำลังใช้งานคุณสมบัตินี้ แม้ว่าอาจจะมีกรณีการใช้งานที่ฉันมองเห็น


มีการใช้สตริงจำนวนมากในงบสวิตช์ แต่เนื่องจากผู้คนไม่สามารถใช้พวกเขาโดยตรงพวกเขาหันไปใช้วิธีแก้ปัญหาอย่างยักษ์ถ้ามีต้นไม้หรือการแปลงเป็น enums วิธีแก้ปัญหาทั้งสองทำให้โค้ดอ่านได้น้อยลง ทั้งสองวิธีเป็นวิธีแก้ปัญหาและเหตุใดจึงใช้วิธีแก้ปัญหาหากวิธีที่ใช้งานจริงแสดงถึงความตั้งใจของโปรแกรมเมอร์ที่ดีขึ้น
Pieter B

@PieterB แม้ว่า Enum จะเพิ่มมูลค่าทางความหมายแทนที่จะเป็นวิธีแก้ปัญหา แต่นำความปลอดภัยประเภท (เช่นพิมพ์ผิดจะถูกจับในเวลารวบรวมมากกว่านำไปสู่ข้อผิดพลาด) นอกจากนี้ยังช่วยให้เราสามารถปรับโครงสร้างอินสแตนซ์ทั้งหมดของสตริงตามที่ใช้ในบริบทนั้นโดยไม่กระทบต่อการใช้งานอื่น ๆ ของสตริงนั้น (ซึ่งอาจเกิดขึ้นบ่อยครั้งกับวัตถุโดเมน)
anotherdave

คำตอบ:


12

เท่าที่ฉันสามารถบอกได้คำถามก็คือทำไมการห่อค่าคงที่สตริงไว้ใน enum ยังไม่เพียงพอที่จะครอบคลุมความต้องการของผู้ใช้ภาษา สิ่งนี้ได้รับการแก้ไขในข้อเสนอคุณสมบัติอย่างเป็นทางการที่ประกาศในรายชื่อผู้รับจดหมายของ JDK 7 (Project Coin)

ตามการอ่านข้อเสนอของฉันทางเลือกของการใช้ enums ถูกไล่ออกบนพื้นดินที่มันแนะนำประเภทขยายตัว เพื่อความสะดวกของคุณส่วนที่เกี่ยวข้องของข้อเสนอจะถูกยกมาด้านล่างพร้อมกับคำชี้แจงที่อยู่ enums ยกมาเป็นตัวหนา :

ข้อได้เปรียบที่สำคัญ: อะไรทำให้ข้อเสนอเปลี่ยนไปในทางที่ดี?

สามารถใช้รูปแบบการเข้ารหัสปกติเพิ่มเติมสำหรับการดำเนินการที่เลือกตามชุดค่าสตริงคงที่ ความหมายของโครงสร้างใหม่ควรชัดเจนกับนักพัฒนา Java

ผลประโยชน์ที่สำคัญ: เหตุใดแพลตฟอร์มจึงดีกว่าหากมีการนำข้อเสนอมาใช้

ประสิทธิภาพที่ดีขึ้นอาจเป็นไปได้สำหรับรหัสการแจกจ่ายตามสตริง

ความผิดพลาดที่สำคัญ: มีค่าใช้จ่ายเสมอ

เพิ่มการใช้งานและทดสอบความซับซ้อนสำหรับคอมไพเลอร์

ทางเลือก: ประโยชน์และข้อได้เปรียบสามารถเกิดขึ้นได้โดยไม่ต้องเปลี่ยนภาษาหรือไม่?

ไม่มี การทดสอบ if-then-else สำหรับความเท่าเทียมกันของสตริงอาจมีราคาแพงและแนะนำ enum สำหรับค่าคงที่แบบเปลี่ยนได้หนึ่งค่าต่อสตริงที่น่าสนใจจะเพิ่มประเภทอื่นให้กับโปรแกรมโดยไม่มีสาเหตุที่ดี ...


ส่วนที่เป็นตัวหนานั้นค่อนข้างน่าประหลาดใจ
Simon Bergot

1
@Simon ดีสำหรับฉันโดยส่วนตัวมันอ่านเป็นการรักษาทางอ้อม "เราจะหลวมการแข่งขันเพื่อ C # ถ้าเรายังคงติดกับวิธี pre-Java5 ในการจัดการกับการพิจารณาเช่นนั้น" :) สำหรับตัวอย่างของ "วิธี Java5 ล่วงหน้า" โปรดดูJDK-1223179: สลับกับสตริง - ส่งในปี 1995 และปิดอย่างรวดเร็วในขณะที่ไม่แก้ไข : "อย่ากลั้นหายใจไม่มีอะไรคล้ายกับแผนของเรา ."
ริ้น

ขอบคุณน่าสนใจมากที่เห็นเหตุผลที่นำเสนอในข้อเสนอ มันยังคงรู้สึกผิดที่จะบอกว่าเรากำลังแนะนำประเภทให้กับโปรแกรม "โดยไม่มีสาเหตุที่ดี" - เราเป็นโปรแกรมเมอร์ OO! :)
anotherdave

5
@ anotherdave "object-oriented" ปรับประเภทการแนะนำเฉพาะเมื่อสิ่งเหล่านี้มีจุดประสงค์ที่มีความหมาย เห็นได้ชัดว่าความเห็นทั่วไปที่ JCP ปรากฎว่าการใช้ enums เป็นตัวห่อหุ้มที่งี่เง่าสำหรับค่าคงที่สตริงในสวิตช์ไม่ถือว่ามีความหมาย
gnat

1
ว้าวฉันแปลกใจ (ในทางที่ดี) เพื่อดูข้อเสนออย่างเป็นทางการที่กำลังโต้ตอบการขยายตัวของประเภท นั่นคือความสดชื่น Bloat ประเภทเป็นปัญหาใหญ่ใน Java
Ben Lee

7

นอกเหนือจากการทำให้โค้ดอ่านง่ายขึ้นแล้วยังมีการเพิ่มประสิทธิภาพที่เป็นไปได้เมื่อเทียบกับif/else ifการเปรียบเทียบ การเปลี่ยนแปลงนั้นคุ้มค่าหรือไม่นั้นขึ้นอยู่กับว่าคุณจะทำการเปรียบเทียบกี่ครั้ง สวิทช์สตริงจะถูกปล่อยออกมาเป็นสองคำแนะนำในการสลับแยก ตัวแรกทำงานกับรหัสแฮชดังนั้นจึงมีแนวโน้มที่จะเป็นไปได้lookupswitchในที่สุดทำให้เกิดO(log n)ความซับซ้อน ที่สองนั้นสมบูรณ์แบบอยู่เสมอO(1) tableswitchดังนั้นความซับซ้อนที่รวมกันจึงยังคงO(log n)อยู่ if/else ifคำแถลงเชิงเส้นตรงเชิงเส้นเดียวจะให้O(n)ความซับซ้อนที่แย่กว่าเล็กน้อย

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


1
ฉันถามมากขึ้นว่าทำไมฉันถึงใช้สวิตช์บนสายอักขระแทนที่จะใช้สวิตช์บน enum ฉันคิดว่าเป็นเรื่องif/elseเลวร้ายอย่างมาก แต่ในตอนนี้ฉันไม่มีเหตุผลอะไรมากมายที่จะใช้มัน
อีก

แต่จากนั้นแผนที่พร้อมกับรูปแบบคำสั่งจะยิ่งทำให้สามารถอ่านได้ง่ายขึ้นด้วยความซับซ้อนเดียวกันเพราะคุณมีประเภทของคำสั่งพิเศษ
SpaceTrucker

3

สวิตช์สำหรับสตริงสามารถใช้เมื่อenumค่าของคุณมาจากภายนอกเช่นเก็บไว้ในฐานข้อมูล

อีกสิ่งที่น่าสังเกตใน JDK 7 switchคือมันมีความสมบูรณ์มากกว่าการif-elseสร้าง

และกรณีการใช้งานที่ดีสำหรับสตริงที่รวดเร็วswitchอาจเป็นการแยกสตรีม JSON / XML เมื่อคุณต้องการสวิตช์จำนวนมากบนโหนดและชนิดของแอ็ตทริบิวต์ ฉันไม่สามารถนึกถึงตัวเลือกที่ดีกว่านี้ได้


1
"สวิตช์สำหรับสตริงไม่สามารถถูกแทนที่ได้เมื่อค่า enum ของคุณมาจากภายนอกคือเก็บไว้ในฐานข้อมูล": คุณสามารถอธิบายรายละเอียดเกี่ยวกับสิ่งนี้ได้หรือไม่? สตริงในคำสั่ง switch จะถูกกำหนดค่าตายตัว: ทันทีที่สตริงในฐานข้อมูลมีการเปลี่ยนแปลงรหัสของคุณจะล้าสมัย
Giorgio

enumในกรณีนี้คุณถูกต้องคุณสามารถใช้งานได้เนื่องจากลักษณะคงที่ของ Java เมื่อฉันกำลังเขียนสิ่งนี้ฉันกำลังคิดเกี่ยวกับRoleห้องสมุดความปลอดภัยซึ่งโดยปกติจะจัดเป็นชั้นเรียนและไม่สามารถใส่เข้าไปenumได้ อีกกรณีหนึ่งคือโค้ด Java / Groovy ที่คอมไพล์แบบไดนามิก - ในสถานการณ์นี้ซึ่งหาได้ยาก แต่สวิตช์สตริงอาจเป็นตัวเลือกที่ดีกว่า
Andrey Chaschev

2

ความง่าย

การสนับสนุน String ใน Switch มีประโยชน์สำหรับการประมวลผลข้อมูลโดยไม่ต้องแปลงเป็น enum หรือif-elseตรรกะ บางครั้งการเปิดใช้งาน String จะง่ายกว่า

จากข้อเสนอคุณสมบัติที่ JDK 7 (Project Coin) รายชื่อผู้รับจดหมาย ( @gnat answer )

การแนะนำ enum สำหรับค่าคงที่แบบสลับได้หนึ่งค่าต่อสตริงที่น่าสนใจจะเพิ่มประเภทอื่นให้กับโปรแกรมโดยไม่มีสาเหตุที่ดี ...

รุ่น If-Else

นี่สั้น แต่หลายif'sเล่มอ่านยาก และนี่คือช้า

if (color.equals("red")) {
    System.out.println("Color is Red");
} else if (color.equals("green")) {
    System.out.println("Color is Green");
} else {
    System.out.println("Color not found");
}

รุ่น Enum

จำเป็นต้องกำหนด Enums นี่เป็นสิ่งที่ดี แต่บางครั้งก็ไม่จำเป็น

enum Color {RED, GREEN}

ประมวลผลตามปกติ

try {
    switch (Color.valueOf(color)) {
        case RED:
            System.out.println("Color is Red");
            break;
        case GREEN:
            System.out.println("Color is Green");
            break;
    }
} catch (IllegalArgumentException e) {
    System.out.println("Color not found");
}

JDK 7 - เงื่อนไขในเวอร์ชันงบสวิตช์

เราสามารถดำเนินการได้โดยไม่ต้องแปลงและกำหนดประเภทเพิ่มเติม

switch (color) {
    case "red":
        System.out.println("Color is Red");
        break;
    case "green":
        System.out.println("Color is Green");
        break;
    default:
        System.out.println("Color not found");
}

7
สิ่งนี้ไม่ได้ตอบคำถาม แต่ทำไมคุณจะใช้สตริงแทนที่จะเป็น enums ที่นี่
Dave Newton

0

การปรับปรุงส่วนใหญ่ในภาษาใด ๆ คือการทำให้โค้ดอ่านง่ายขึ้น ฉันชอบรหัสที่อ่านได้มากกว่าแฟนซีทุกวัน

คุณอาจไม่เชื่อสิ่งนี้ แต่ลอง:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " (dgerman@indiana.edu)";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " (asengupt@indiana.edu)";
    }
  },

  // and on for the rest...

  private String name;

  public JettStaff(String n) { this.name = n; }
}

JettStaff x = JettStaff.SUZANNE;
System.out.println(x);

ฉันไม่ชัดเจนในตัวอย่างโค้ดของคุณและความคิดเห็นของคุณด้านบน คุณหมายถึง Enum เป็นตัวอย่างของสิ่งที่อ่านยากหรือไม่
อีก


2
นี่คือสิ่งที่วางแผนไว้อย่างมาก คุณแสร้งว่า enum ไม่มีฟิลด์อีเมลหรือว่านี่ไม่ใช่คลาส
Dave Newton

4
@ user2860598 หากคุณพยายามทำแต้มให้ใช้ตัวอย่างที่เกี่ยวข้อง นอกจากนี้ยังไม่ได้อยู่ที่ไขมันนิ้วสตริงคงที่
เดฟนิวตัน

1
@ user2860598 คำตอบที่คุณเชื่อมโยงนั้นบอกว่ามีการเปิดตัวแล้วและก่อนหน้านี้พวกเขาสามารถ "ประมาณ" ด้วย Enum ประเด็นของฉันคือการใช้ Enum ดูเหมือนว่าจะยังดีกว่าถึงแม้จะมีการแนะนำ
Anotherdave

0

Enums นั้นยอดเยี่ยมและคุณควรใช้ Strings แทนเมื่อคุณมีความสามารถ แต่มีบางครั้งที่คุณทำไม่ได้ตัวอย่างเช่นเมื่อคุณต้องทำงานกับวัตถุภายนอกบางตัวที่มาจากนอก Java ลองนึกภาพว่าคุณต้องแยกวิเคราะห์บางอย่าง เช่นเดียวกับการตอบกลับของเซิร์ฟเวอร์การกำหนดค่าไฟล์บันทึกหรือสิ่งที่คล้ายกัน: คุณมีตัวเลือกมากมายที่คุณกำลังมองหาและไม่มีทางที่จะเป็นไปได้ ดังนั้นใน Java <7 คุณจะต้องติดอยู่กับมัน

  if (something.equals("foo")) {
    // foo processing
  } else 
  if (something.equals("bar")) {
   // bar processing
  }

คุณยังสามารถใช้ enums ในกรณีนี้โดยเพียงแค่พยายามรับค่าเหล่านั้นตามชื่อและ / หรือโดยการกำหนด String-> Enum ประจำ แต่บางครั้งก็เป็นไปไม่ได้หรือไม่จริง (เช่นเมื่อคุณต้องสร้าง enums มากเกินไป)

TLDR : คุณควรใช้ Enums อย่างแน่นอนเมื่อคุณทำงานกับโค้ด Java อย่างหมดจด แต่ไม่สามารถทำกับวัตถุภายนอกได้เสมอไป ฉันหวังว่าคำอธิบายของฉันจะสมเหตุสมผล


หากคุณกำลังจัดการกับข้อมูลภายนอกและคุณรู้พอที่จะรู้ว่าคุณต้องการอะไรในifงบของคุณคุณควรจะตัดมันต่อไปซึ่งหมายความว่าคุณยังคงสามารถใช้ enums หรือรูปแบบคำสั่งเป็นต้น
Dave Newton

@ DaveNewton ใช่คุณยังคงสามารถใช้ enums ได้ แต่ตามที่ฉันได้ระบุไว้ในคำตอบของฉันบางครั้งมันก็ไม่ได้ใช้งานได้จริงในกรณีที่คุณต้องสร้าง Enums ที่แขวนอยู่เพื่อที่จะใช้เพียงครั้งเดียวในการแยกวิเคราะห์

@dimoniy แต่ถ้าคุณต้องสร้างค่า Enum 100s นั่นไม่ได้หมายความว่าจะเป็นทางเลือกที่เปลี่ยนได้ที่คุณจะต้องมีคำสั่ง case 100s หรือไม่? หากมีหลายตัวแปรที่ฉันต้องการความปลอดภัยประเภทของ enums แน่นอน
อีก

0

ฉันไม่เห็นด้วยกับความเห็นว่าเป็นโค้ดที่สะอาดและอ่านได้เมื่อคุณใช้Stringsในคำสั่ง switch และคิดว่ามันเป็นวิธีการเขียนโปรแกรมที่ไม่ดี หากคุณเปลี่ยนค่าที่คุณใช้ในการจัดเก็บคุณจะต้องเปลี่ยนมันทุกสวิตช์หรือถ้าเกิดเหตุการณ์อื่น สิ่งนี้ไม่ดีเนื่องจากคุณใส่ค่าฮาร์ดโค้ดลงในรหัสของคุณทุกครั้ง คุณจะทำอย่างไรถ้าวันหนึ่งคุณตัดสินใจที่จะเปลี่ยนหนึ่งในค่าที่กำหนดรหัสยากเหล่านี้ ค้นหาและแทนที่ทุกสำเนาหรือไม่

หากคุณมีค่าฮาร์โค้ดที่คุณใช้คำสั่ง if-elseif การใช้ค่าดั้งเดิมคงที่สำหรับพวกเขานั้นดีกว่าก่อนหน้า Java 1.5 เพียงเพราะมันนำความปลอดภัยมาให้

ตกลงจะมีสถานการณ์ที่คุณจะได้รับค่าสตริง (จากคำขอ HTTP, ไฟล์ ฯลฯ ) และแปลงเป็นค่าดั้งเดิมคือความเจ็บปวด แต่Enumตอนนี้ทำงานได้ดี เพราะเมื่อคุณต้องการเปลี่ยนค่าที่คุณเก็บไว้ใน Enum เพียงแค่เปลี่ยนเมื่อคุณประกาศ ไม่จำเป็นต้องเปลี่ยนอะไรในรหัสของคุณ (แน่นอนคุณต้องเปลี่ยนค่าที่เก็บไว้ที่อื่น)

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


-1

ถ้าคุณรู้ว่าข้อมูลที่มาในและว่ามันอาจจะเป็นของ 5 Enumรัฐแล้วใช้ อย่างไรก็ตามหากสถานะที่เป็นไปได้อาจมากกว่า 9000 และคุณต้องการเพียง 42 เท่านั้นการใช้สวิตช์จะดีกว่าเพราะคุณไม่ต้องการพิมพ์สถานะเหล่านั้นทั้งหมด

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

แต่ทำไมพวกเขาถึงแนะนำมันตอนนี้ มันเป็นเพียงการเปลี่ยนแปลงที่อนุญาตให้ใช้โค้ดที่สะอาดกว่า

ใน 1.5 พวกเขายังอนุญาตให้คุณสร้างเนื้อหาที่กำหนดเองสำหรับ Enums อีกด้วย


แต่คุณจะไม่เพียงกำหนดค่าที่เป็นไปได้อีก 8958 รายการให้กับสถานะ Enum หนึ่งรายการหรือไม่
อีก

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

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