Java enum - ทำไมต้องใช้ toString แทนที่จะเป็นชื่อ


171

ถ้าคุณดูใน enum api ที่วิธีการname()มันบอกว่า:

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

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


4
คุณสามารถแทนที่toString()ใน enum ของคุณ แต่ไม่มีใครสามารถขยายและแทนที่ได้ คุณไม่สามารถขยาย enums ได้
Erick G. Hagstrom

คำตอบ:


198

ขึ้นอยู่กับสิ่งที่คุณต้องการจะทำกับค่าที่ส่งคืน:

  • หากคุณต้องการรับชื่อที่แน่นอนที่ใช้ในการประกาศค่าคงที่ enum คุณควรใช้name()ตามที่toStringอาจจะถูก overriden
  • หากคุณต้องการพิมพ์ค่าคง enum ด้วยวิธีที่เป็นมิตรกับผู้ใช้คุณควรใช้ค่าtoStringที่อาจมีค่าเกิน (หรือไม่!)

เมื่อฉันรู้สึกว่ามันอาจทำให้สับสนฉันมีgetXXXวิธีเฉพาะเจาะจงมากขึ้นเช่น:

public enum Fields {
    LAST_NAME("Last Name"), FIRST_NAME("First Name");

    private final String fieldDescription;

    private Fields(String value) {
        fieldDescription = value;
    }

    public String getFieldDescription() {
        return fieldDescription;
    }
}

1
นี่เป็นที่ยอมรับ แม้ว่าพวกเขาจะปล่อยให้ enum มีคลาสพื้นฐานก็จะง่ายกว่า
ralphgabb

55

ใช้name()เมื่อคุณต้องการทำการเปรียบเทียบหรือใช้ค่า hardcoded สำหรับการใช้ภายในบางอย่างในรหัสของคุณ

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

จาก javadoc (เน้นที่เหมือง):

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


23

name()เป็น "ในตัว" enumวิธีการของ เป็นขั้นสุดท้ายและคุณไม่สามารถเปลี่ยนการใช้งานได้ มันจะส่งกลับชื่อของค่าคงที่ enum ตามที่เขียนไว้เช่นในตัวพิมพ์ใหญ่โดยไม่มีช่องว่าง ฯลฯ

เปรียบเทียบและMOBILE_PHONE_NUMBER Mobile phone numberเวอร์ชันใดที่สามารถอ่านได้มากกว่า ฉันเชื่อว่าอันที่สอง นี่คือความแตกต่าง: name()ผลตอบแทนเสมอMOBILE_PHONE_NUMBER, อาจจะแทนที่การกลับมาtoString()Mobile phone number


16
ไม่ถูกต้อง !! toString () ผลตอบแทนMobile phone numberก็ต่อเมื่อคุณแทนที่มันเพื่อกลับค่าดังกล่าว มิฉะนั้นจะส่งคืนMOBILE_PHONE_NUMBER
spauny

2
@spayny toString()ก็เป็นที่ชัดเจนว่าคุณมีการแทนที่ การดักจับname()นั้นไม่สามารถเขียนทับได้เนื่องจากมันเป็นครั้งสุดท้าย
AlexR

13
@AlexR คุณอาจจำเป็นต้องรวมความคิดเห็นข้างต้นของคุณในคำตอบเพื่อให้ถูกต้อง 100%
artfullyContrived

5
ฉันเห็นด้วยกับ @artfullyContrived เพราะฉันไม่เห็นจนกว่าฉันจะอ่านความคิดเห็นของคุณ
martinatime

13

ในขณะที่คนส่วนใหญ่ทำตามคำแนะนำของ javadoc อย่างสุ่มสี่สุ่มห้ามีสถานการณ์เฉพาะเจาะจงมากที่คุณต้องการหลีกเลี่ยง toString () ตัวอย่างเช่นฉันใช้ enums ในรหัส Java ของฉัน แต่พวกเขาจำเป็นต้องต่อเนื่องกับฐานข้อมูลและกลับมาอีกครั้ง ถ้าฉันใช้ toString () ฉันก็จะได้รับพฤติกรรมที่แทนที่ด้วยเทคนิคโดยที่คนอื่น ๆ ได้ชี้ให้เห็น

นอกจากนี้หนึ่งสามารถยกเลิกการทำให้เป็นอันดับจากฐานข้อมูลตัวอย่างเช่นนี้ควรทำงานใน Java:

MyEnum taco = MyEnum.valueOf(MyEnum.TACO.name());

ในขณะที่สิ่งนี้ไม่ได้รับประกัน:

MyEnum taco = MyEnum.valueOf(MyEnum.TACO.toString());

โดยวิธีการที่ฉันพบว่ามันแปลกมากสำหรับ Javadoc ที่จะพูดอย่างชัดเจนว่า "โปรแกรมเมอร์ส่วนใหญ่ควร" ฉันพบกรณีการใช้งานน้อยมากใน toString ของ enum หากผู้คนใช้ชื่อ "มิตร" ซึ่งชัดเจนว่าเป็นกรณีการใช้งานที่ไม่ดีเพราะพวกเขาควรใช้บางสิ่งที่เข้ากันได้กับ i18n ซึ่งในกรณีส่วนใหญ่ ใช้ชื่อ () วิธีการ


2
ขอบคุณสำหรับคำตอบ. เกือบ 5 ปีแล้วที่ฉันถามคำถามนี้และฉันยังไม่ได้ใช้เมธอด toString () สำหรับ enum! 99% ของเวลาที่ฉันใช้ enums ตรงกับสิ่งที่คุณอธิบาย: serializing และ deserialising enum ชื่อไป / จากฐานข้อมูล
spauny

5

ตัวอย่างที่ใช้งานได้จริงเมื่อ name () และ toString () ทำให้เข้าใจถึงความแตกต่างคือรูปแบบที่ใช้ enum ที่มีค่าเดียวเพื่อกำหนด singleton มันดูน่าประหลาดใจในตอนแรก แต่ก็สมเหตุสมผลดี:

enum SingletonComponent {
    INSTANCE(/*..configuration...*/);

    /* ...behavior... */

    @Override
    String toString() {
      return "SingletonComponent"; // better than default "INSTANCE"
    }
}

ในกรณีเช่นนี้:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better

ใช่คุณพูดถูก ... ตัวอย่างที่ดีคือ
Guedic

4

name () เป็นอักษรตัวอักษรในรหัส java ของ enum ซึ่งหมายความว่ามันถูก จำกัด ไว้ที่สตริงที่สามารถปรากฏในโค้ดจาวาของคุณ แต่สตริงที่ต้องการทั้งหมดนั้นไม่สามารถแสดงเป็นโค้ดได้ ตัวอย่างเช่นคุณอาจต้องการสตริงที่ขึ้นต้นด้วยตัวเลข ชื่อ () จะไม่สามารถรับสตริงนั้นได้สำหรับคุณ


-1

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

@AllArgsConstructor
@Getter
public enum RetroDeviceStatus {
    DELIVERED(0,"Delivered"),
    ACCEPTED(1, "Accepted"),
    REJECTED(2, "Rejected"),
    REPAIRED(3, "Repaired");

    private final Integer value;
    private final String stringValue;

    @Override
    public String toString() {
        return this.stringValue;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.