ใช้ค่า Enum เป็นตัวอักษรสตริง


389

วิธีที่ดีที่สุดในการใช้ค่าที่เก็บไว้ใน Enum เป็นตัวอักษร String คืออะไร ตัวอย่างเช่น:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3
}

แล้วต่อมาผมสามารถใช้เพื่อกลับแสดงสตริงในฐานะที่เป็นMode.mode1 mode1โดยไม่ต้องโทรMode.mode1.toString()ออก

คำตอบ:


646

คุณทำไม่ได้ ฉันคิดว่าคุณมีสี่ตัวเลือกที่นี่ ทั้งสี่ข้อเสนอทางออก แต่ด้วยวิธีที่แตกต่างกันเล็กน้อย ...

ตัวเลือกที่หนึ่ง: ใช้ built-in name()บน enum นี่เป็นสิ่งที่สมบูรณ์แบบหากคุณไม่ต้องการรูปแบบการตั้งชื่อพิเศษใด ๆ

    String name = Modes.mode1.name(); // Returns the name of this enum constant, exactly as declared in its enum declaration.

ตัวเลือกที่สอง: เพิ่มคุณสมบัติการเอาชนะลงใน enums ของคุณหากคุณต้องการการควบคุมที่มากขึ้น

public enum Modes {
    mode1 ("Fancy Mode 1"),
    mode2 ("Fancy Mode 2"),
    mode3 ("Fancy Mode 3");

    private final String name;       

    private Modes(String s) {
        name = s;
    }

    public boolean equalsName(String otherName) {
        // (otherName == null) check is not needed because name.equals(null) returns false 
        return name.equals(otherName);
    }

    public String toString() {
       return this.name;
    }
}

ตัวเลือกที่สาม: ใช้ finals คงที่แทน enums:

public final class Modes {

    public static final String MODE_1 = "Fancy Mode 1";
    public static final String MODE_2 = "Fancy Mode 2";
    public static final String MODE_3 = "Fancy Mode 3";

    private Modes() { }
}

ตัวเลือกที่สี่: อินเทอร์เฟซมีทุกฟิลด์สาธารณะคงที่และสุดท้าย:

public interface Modes {

    String MODE_1 = "Fancy Mode 1";
    String MODE_2 = "Fancy Mode 2";
    String MODE_3 = "Fancy Mode 3";  
}

46
คำตอบนี้เป็นความจริงที่ผิด: คุณสามารถโทรหา.name()See: stackoverflow.com/a/6667365/887836
Alex

3
@ kato2 ไม่ถูกต้อง วิธีการ. name () ถูกสร้างขึ้นโดยอัตโนมัติโดยคอมไพเลอร์
Sean Patrick Floyd

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

awser ของ @Ryan Stewart ต้องใช้รหัสน้อยลงและรหัสน้อย == โอกาสในการเกิดข้อผิดพลาดน้อยลง
Eric

4
อย่าใช้อินเทอร์เฟซเพื่อระงับค่าคงที่: Java ที่มีประสิทธิภาพ (รุ่นที่ 3) แนะนำให้ "ใช้ส่วนต่อประสานเท่านั้นเพื่อกำหนดประเภท" (รายการที่ 22)
Olivier Grégoire

481

ทุก enum มีทั้งชื่อ () และวิธี valueOf (String) อดีตส่งกลับชื่อสตริงของ enum และหลังให้ค่า enum ที่มีชื่อเป็นสตริง นี่เป็นสิ่งที่คุณกำลังมองหาใช่ไหม

String name = Modes.mode1.name();
Modes mode = Modes.valueOf(name);

นอกจากนี้ยังมีค่าคงที่คงที่ (คลาส, สตริง) บน Enum เองดังนั้นคุณสามารถใช้

Modes mode = Enum.valueOf(Modes.class, name);

50
นี่ควรเป็นคำตอบ! การใช้บางสิ่งเช่น A ("A") อาจเป็นสาเหตุของข้อผิดพลาดและเป็นงานพิเศษที่ไร้เหตุผล!
Firzen

12
@ สิบสามไม่ได้ถ้าค่าสตริงได้รับอนุญาตให้มีช่องว่างหรือยัติภังค์ซึ่งเป็นกรณีที่some-really-long-stringมา
ceving

@ceving คำถามไม่ได้เป็นประโยคที่ดีเกี่ยวกับช่องว่างและยัติภังค์ คำถามแสดงตัวอย่างที่มียัติภังค์ แต่ไม่ถามวิธีสร้าง Enum โดยใช้ค่าที่มียัติภังค์ คำถามจะถามวิธีรับค่าสตริงโดยไม่ต้องเรียก toString โดยไม่ต้องระบุค่ายัติภังค์เป็นข้อกำหนด ที่กล่าวว่าฉันคิดว่านี่อาจเป็นคำตอบที่ดีกว่าหากมีการแก้ไขกล่าวถึงว่าค่า Enum ยังคงต้องปฏิบัติตามกฎการตั้งชื่อ Java และจะต้องใช้สิ่งที่กล่าวถึงในคำตอบที่ยอมรับถ้าต้องการตัวอักษรดังกล่าว
Hazok

ฉันต้องการเพิ่มลิงค์ไปยังmkyongผู้ใช้valueOf(String)วิธีร่วมกับtoUpperCase(Locale)เพื่อให้แน่ใจว่าการแปลงสตริง
รหัสที่ไม่รู้จัก

2
เหตุผลที่ผู้คนจำนวนมากชอบที่จะเข้าถึงคุณสมบัติของ Enum.name () คือตรรกะที่อยู่รอบ ๆ Enum.name () นั้นเป็นเหตุผลที่ดีสำหรับชื่อที่มีค่า หากรหัสทุกการเปลี่ยนแปลงในอนาคตสิ่งนี้อาจกลายเป็นปัญหาที่ไม่สำคัญที่จะหลีกเลี่ยงเนื่องจากตรรกะก่อนหน้านี้ทั้งหมดจะหยุดการเปลี่ยนแปลงในการตั้งค่า Enum การเอาชนะและใช้วิธีการ toString () ช่วยให้นักพัฒนาสามารถควบคุมค่าที่ใช้งานได้มากขึ้นรวมถึงการทำซ้ำอักขระชื่อตัวแปรที่ไม่ถูกต้อง ฯลฯ อย่าลืมที่จะแทนที่ valueOf () ด้วย
แบ่งแยกไม่ได้

79

คุณสามารถแทนที่toString()วิธีสำหรับแต่ละค่า enum

ตัวอย่าง:

public enum Country {

  DE {
    @Override
    public String toString() {
      return "Germany";
    }
  },
  IT {
    @Override
    public String toString() {
      return "Italy";
    }
  },
  US {
    @Override
    public String toString() {
      return "United States";
    }
  }

}

การใช้งาน:

public static void main(String[] args) {
  System.out.println(Country.DE); // Germany
  System.out.println(Country.IT); // Italy
  System.out.println(Country.US); // United States
}

2
ฉันชอบสิ่งนี้. ไม่มีเหตุผลที่จะไม่ใช้ enum เป็นคลาสที่มีฟังก์ชั่นเพิ่มเติมเช่นรับรายการค่าทั้งหมดรับสตริงของแต่ละประเภทเป็นต้น
diegosasw

8
น่าเกลียดและไม่สามารถใช้ซ้ำได้ ดีกว่าการให้ค่าสตริงเป็นตัวสร้างสำหรับประเทศแล้วแทนที่เมธอด toString () สำหรับ enum
greg7gkb

4
นี่เป็นเทคนิคที่ดีเมื่อคุณมีการแจงนับค่อนข้างมากและต้องการแทนที่สิ่งที่พิมพ์สำหรับสมาชิกหนึ่งหรือสองคน
Donal Fellows

3
มันไม่ได้ปรับขนาดเลย อย่าทำอย่างนี้
sebnukem

1
นี่เหมาะสมกับฉัน
hanzolo

35

ตามที่ Benny Neugebauer กล่าวถึงคุณสามารถเขียนทับ theString () ได้ อย่างไรก็ตามแทนที่จะเขียนทับ toString สำหรับแต่ละฟิลด์ enum ฉันชอบสิ่งนี้มากกว่านี้:

public enum Country{
    SPAIN("España"),
    ITALY("Italia"),
    PORTUGAL("Portugal");


    private String value;

    Country(final String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.getValue();
    }
}

คุณสามารถเพิ่มวิธีการแบบคงที่เพื่อดึงข้อมูลฟิลด์ทั้งหมดเพื่อพิมพ์ทั้งหมด ฯลฯ เพียงแค่เรียก getValue เพื่อรับสตริงที่เกี่ยวข้องกับแต่ละรายการ Enum



21
public enum Modes {
  MODE1("Mode1"),
  MODE2("Mode2"),
  MODE3("Mode3");

 private String value;
 public String getValue() {
    return value;
   }
 private Modes(String value) {
  this.value = value;
 } 
}

คุณสามารถโทรได้เหมือนด้านล่างทุกที่ที่คุณต้องการรับค่าเป็นสตริงจาก enum

Modes.MODE1.getvalue();

สิ่งนี้จะคืนค่า "Mode1" เป็นสตริง


6

คุณสามารถใช้งานได้Mode.mode1.name()บ่อยครั้งที่คุณไม่จำเป็นต้องทำสิ่งนี้

Mode mode =
System.out.println("The mode is "+mode);

6
เป็นที่น่าสังเกตว่าตัวดำเนินการ + จะเรียก toString () บน enum ไม่ใช่ชื่อ () และ toString () อาจถูกแทนที่เพื่อส่งคืนสิ่งอื่นที่ไม่ใช่ชื่อ (แม้ว่าจะไม่เป็นที่ต้องการ)
JB Nizet

1
ทั้งสองname()และtoString()สามารถ overriden แต่หวังว่านี้จะชัดเจนจากการอ่านรหัสสำหรับenumหากสิ่งที่เกิดขึ้น
Peter Lawrey

9
ไม่ใช่ชื่อ () ถือเป็นที่สิ้นสุดและจะส่งคืนชื่อของ enum ตามที่ประกาศในการประกาศ enum เสมอ
JB Nizet

1
@JB Nizet คุณพูดถูก เป็นname() finalขอบคุณสำหรับการแก้ไขฉัน :)
Peter Lawrey

6

เท่าที่ฉันรู้วิธีเดียวที่จะได้ชื่อก็คือ

Mode.mode1.name();

อย่างไรก็ตามหากคุณต้องการวิธีนี้จริงๆคุณสามารถทำได้:

public enum Modes {
    mode1 ("Mode1"),
    mode2 ("Mode2"),
    mode3 ("Mode3");

    private String name;       

    private Modes(String s) {
        name = s;
    }
}

1
แต่ในกรณีนี้ยังไม่ประเภทMode.mode1 String
Larry

โอ้ใช่. คุณต้องการเมธอด getName () ซึ่งเป็นการเอาชนะวัตถุประสงค์ดังนั้นไม่คุณไม่สามารถทำได้
Jake Roussel

"name" เป็นชื่อฟิลด์ที่ไม่ถูกต้องเป็นฟิลด์มาตรฐานของ enum
Wooff

6

สำหรับ enums ของฉันฉันไม่ชอบคิดว่าพวกเขาจะถูกจัดสรรด้วย 1 String ต่อคน นี่คือวิธีที่ฉันใช้เมธอด toString () บน enums

enum Animal
{
    DOG, CAT, BIRD;
    public String toString(){
        switch (this) {
            case DOG: return "Dog";
            case CAT: return "Cat";
            case BIRD: return "Bird";
        }
        return null;
    }
}

1
การขว้างข้อยกเว้นรันไทม์จะดีกว่าแทนที่จะส่งคืน null เนื่องจากควรเป็นรหัสที่ไม่สามารถเข้าถึงได้
ค่าเช่า

returnซ้ำซ้อนเพราะสวิทช์ใน enums กับ enums ทั้งหมดจะยุติ
Danon

5

คุณสามารถใช้:

""+ Modes.mode1

ฉันไม่แน่ใจ 100% เกี่ยวกับเรื่องนี้ แต่เท่าที่ความรู้ของฉันไปสู่นักแสดงนี้ไม่จำเป็นใช่ไหม? การเชื่อมสตริงว่างกับตัวแปรอื่นควรเรียกการแปลงโดยอัตโนมัติหรือมีข้อยกเว้นสำหรับกฎนี้หรือไม่
รหัสที่ไม่รู้จัก

1
"" + Modes.mode1คุณมีสิทธิรุ่นที่ถูกต้องควรจะเป็น ฉันแก้ไขคำตอบ
บัดดี้

คำตอบของ EB ก็มีประโยชน์เช่นกันเมื่อนึกถึง python idiom ''.join()
anthropic android

5

ทางออกของฉันสำหรับปัญหาของคุณ!

import java.util.HashMap;
import java.util.Map;

public enum MapEnumSample {
    Mustang("One of the fastest cars in the world!"), 
    Mercedes("One of the most beautiful cars in the world!"), 
    Ferrari("Ferrari or Mercedes, which one is the best?");

    private final String description;
    private static Map<String, String> enumMap;

    private MapEnumSample(String description) {
        this.description = description;
    }

    public String getEnumValue() {
        return description;
    }

    public static String getEnumKey(String name) {
        if (enumMap == null) {
            initializeMap();
        }
        return enumMap.get(name);
    }

    private static Map<String, String> initializeMap() {
        enumMap = new HashMap<String, String>();
        for (MapEnumSample access : MapEnumSample.values()) {
            enumMap.put(access.getEnumValue(), access.toString());
        }
        return enumMap;
    }

    public static void main(String[] args) {

        // getting value from Description
        System.out.println(MapEnumSample.getEnumKey("One of the fastest cars in the world!"));

        // getting value from Constant
        System.out.println(MapEnumSample.Mustang.getEnumValue());

        System.out.println(MapEnumSample.getEnumKey("One of the most beautiful cars in the world!"));
        System.out.println(MapEnumSample.Mercedes.getEnumValue());

        // doesnt exist in Enum
        System.out.println("Mustang or Mercedes, which one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Mustang or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mustang, which one is the best?") + " is the best!.");

        // exists in Enum
        System.out.println("Ferrari or Mercedes, wich one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") + " is the best!");

    }
}

ดูเหมือนว่าปัญหาของ OP จะได้รับการแก้ไขเมื่อ 4 ปีที่แล้ว แต่ยินดีต้อนรับสู่ StackOverflow :)
TDG

1
ขอบคุณเพียงเพื่อช่วยใครเหมือนผมมองหาคำตอบวัตถุประสงค์มากขึ้นเพื่อปัญหาเก่า :)
Renan Galdino ดาซิลวา

3

Enum เป็นคลาสพิเศษเล็กน้อย Enums สามารถเก็บฟิลด์เพิ่มเติมใช้เมธอดเป็นต้นตัวอย่างเช่น

public enum Modes {
    mode1('a'),
    mode2('b'),
    mode3('c'),
    ;
    char c;

    private Modes(char c) {
        this.c = c;
    }
    public char character() {
        return c;
    }
}

ตอนนี้คุณสามารถพูดได้:

System.out.println(Modes.mode1.character())

และดูผลลัพธ์: a


3
package com.common.test;

public  enum Days {


    monday(1,"Monday"),tuesday(2,"Tuesday"),wednesday(3,"Wednesday"),
    thrusday(4,"Thrusday"),friday(5,"Friday"),saturday(6,"Saturday"),sunday(7,"Sunday");

    private int id;
    private String desc;


    Days(int id,String desc){
        this.id=id;
        this.desc=desc;
    }

    public static String getDay(int id){

        for (Days day : Days.values()) {
            if (day.getId() == id) {
                return day.getDesc();
            }
        }
        return null;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }



};

1
คุณช่วยอธิบายเกี่ยวกับวิธีแก้ไขปัญหาได้ไหม?
ฟานี

คุณสามารถเรียก enum นี้ได้ทุกที่โดยใช้บรรทัดนี้: int id = 1; String dayName = Days.getDay (id); รหัสผ่านที่นี่ มันจะส่งคืนคำอธิบายสำหรับรหัสนั่นคือ "วันอังคาร"

2

วิธีนี้ควรใช้กับenum:

public enum MyEnum {
    VALUE1,
    VALUE2,
    VALUE3;

    public int getValue() {
        return this.ordinal();
    }

    public static DataType forValue(int value) {
        return values()[value];
    }

    public String toString() {
        return forValue(getValue()).name();
    }
}

2
public enum Environment
{
    PROD("https://prod.domain.com:1088/"),
    SIT("https://sit.domain.com:2019/"),
    CIT("https://cit.domain.com:8080/"),
    DEV("https://dev.domain.com:21323/");

    private String url;

    Environment(String envUrl) {
        this.url = envUrl;
    }

    public String getUrl() {
        return url;
    }
}

String prodUrl = Environment.PROD.getUrl();

มันจะพิมพ์:

https://prod.domain.com:1088/

การออกแบบสำหรับค่าคงที่สตริง enum นี้ทำงานในกรณีส่วนใหญ่


0

หลังจากพยายามมาหลายครั้งฉันก็มาพร้อมกับทางออกนี้

public static enum Operation {

    Addition, Subtraction, Multiplication, Division,;

    public String getUserFriendlyString() {
        if (this==Addition) {
            return " + ";
        } else if (this==Subtraction) {
            return " - ";
        } else if (this==Multiplication) {
            return " * ";
        } else if (this==Division) {
            return " / ";
        }
        return "undefined";
       }
}

0

คุณสามารถลองสิ่งนี้:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    public String toString(){
        switch(this) {
            case some-really-long-string:
                return "some-really-long-string";
            case mode2:
                return "mode2";
            default: return "undefined";
        }
    }

}


0

ฉันพบสิ่งนี้ง่ายกว่าสำหรับการป้องกันข้อผิดพลาดประเภท:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    String str;

    Modes(){
        this.str = super.name();
    }

    @Override
    @NonNull
    public String toString() {
        return str;
    }

อย่างไรก็ตาม - สิ่งนี้อาจใช้งานได้เมื่อคุณจำเป็นต้องใช้ String ใน log / println หรือเมื่อใดก็ตามที่ java รวบรวมเมธอด toString () โดยอัตโนมัติ แต่บนโค้ดบรรทัดเช่นนี้ ->

// sample method that require (string,value)
intent.putExtra(Modes.mode1 ,shareElement.getMode()); // java error
// first argument enum does not return value

แทนดังกล่าวข้างต้นคุณยังจะต้องขยาย enum และใช้.name() ในกรณีเหล่านี้:

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