Sử dụng các giá trị Enum làm chuỗi ký tự


389

Cách tốt nhất để sử dụng các giá trị được lưu trữ trong Enum dưới dạng chuỗi ký tự là gì? Ví dụ:

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

Sau đó, tôi có thể sử dụng Mode.mode1để trả về đại diện chuỗi của nó là mode1. Mà không phải tiếp tục gọi Mode.mode1.toString().

Câu trả lời:


646

Bạn không thể. Tôi nghĩ rằng bạn có BỐN tùy chọn ở đây. Cả bốn đều đưa ra một giải pháp nhưng với cách tiếp cận hơi khác ...

Tùy chọn Một: sử dụng tích hợp name()trên enum. Điều này là hoàn toàn tốt nếu bạn không cần bất kỳ định dạng đặt tên đặc biệt.

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

Tùy chọn Hai: thêm thuộc tính ghi đè vào enum của bạn nếu bạn muốn kiểm soát nhiều hơn

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;
    }
}

Tùy chọn thứ ba: sử dụng trận chung kết tĩnh thay vì 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() { }
}

Tùy chọn Bốn: giao diện có mọi trường công khai, tĩnh và cuối cùng:

public interface Modes {

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

46
Câu trả lời này thực tế là sai: như bạn có thể gọi .name()See: stackoverflow.com/a/6667365/887836
Alex

3
@ kato2 không đúng. Phương thức .name () được tạo tự động bởi trình biên dịch
Sean Patrick Floyd

10
JavaDoc: String java.lang.Enum.name () Trả về tên của hằng số enum này, chính xác như được khai báo trong khai báo enum của nó. Hầu hết các lập trình viên nên sử dụng phương thức toString theo sở thích này, vì phương thức toString có thể trả về một tên thân thiện hơn với người dùng. Phương pháp này được thiết kế chủ yếu để sử dụng trong các tình huống chuyên biệt trong đó tính chính xác phụ thuộc vào việc lấy tên chính xác, sẽ không thay đổi từ phát hành đến phát hành. Trả về: tên của hằng số enum này
SuperRetro

Awser của @Ryan Stewart yêu cầu ít mã hơn và ít mã hơn == ít khả năng xảy ra lỗi hơn
Eric

4
Không sử dụng các giao diện để giữ các hằng số: Java hiệu quả (phiên bản thứ 3) khuyến nghị "chỉ sử dụng các giao diện để xác định loại" (mục 22).
Olivier Grégoire

481

Mỗi enum có cả phương thức name () và valueOf (String). Cái trước trả về tên chuỗi của enum và cái sau cho giá trị enum có tên là chuỗi. Đây có giống như những gì bạn đang tìm kiếm?

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

Ngoài ra còn có một giá trị tĩnh (Lớp, Chuỗi) trên chính Enum, vì vậy bạn cũng có thể sử dụng

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

50
ĐÂY nên là một TRẢ LỜI! Sử dụng một cái gì đó như A ("A") có thể là nguồn gốc của lỗi và đó là công việc bổ sung vô nghĩa!
Firzen

12
@Firzen không nếu giá trị chuỗi được phép chứa dấu cách hoặc dấu gạch nối, đó là trường hợp trong some-really-long-string.
ceving

@ceving Câu hỏi không được đặt đúng về không gian và dấu gạch nối. Các câu hỏi cho thấy một ví dụ được gạch nối, nhưng không hỏi cách tạo Enum bằng các giá trị được gạch nối. Thay vào đó, câu hỏi hỏi làm thế nào để có được giá trị Chuỗi mà không phải gọi toString mà không chỉ định giá trị gạch nối là một yêu cầu. Điều đó nói rằng, tôi nghĩ rằng đây có thể là một câu trả lời tốt hơn nếu nó được sửa đổi để đề cập rằng các giá trị Enum vẫn phải tuân theo các quy tắc đặt tên Java và sẽ cần sử dụng một cái gì đó được đề cập trong câu trả lời được chấp nhận nếu các ký tự đó được yêu cầu.
Hazok 15/05/2015

Tôi muốn thêm một liên kết đến mkyong , người sử dụng valueOf(String)phương thức kết hợp với toUpperCase(Locale)để đảm bảo chuyển đổi Chuỗi.
Id không xác định

2
Lý do rất nhiều người thích cách tiếp cận thuộc tính hơn Enum.name () là logic dựa trên Enum.name () sau đó là mãi mãi trong sự thương xót của các tên giá trị. Nếu mã mỗi thay đổi trong tương lai, điều này có thể trở thành một vấn đề không hề nhỏ để giải quyết vì tất cả logic trước đó sẽ phá vỡ các thay đổi đối với giá trị Enum. Ghi đè và sử dụng cách tiếp cận toString () cho phép nhà phát triển kiểm soát nhiều hơn các giá trị được sử dụng bao gồm sao chép, ký tự tên biến không hợp lệ, v.v. Chỉ cần đừng quên ghi đè valueOf ().
không thể chia sẻ

79

Bạn có thể ghi đè toString()phương thức cho từng giá trị enum.

Thí dụ:

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";
    }
  }

}

Sử dụng:

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
Tôi thích điều này. Không có lý do gì để không sử dụng enum như một lớp có chức năng xa hơn như lấy danh sách tất cả các giá trị, lấy chuỗi của từng loại, v.v.
diegosasw

8
Xấu xí và không thể tái sử dụng Tốt hơn nhiều để cung cấp một giá trị chuỗi như hàm tạo cho Quốc gia và sau đó ghi đè phương thức toString () cho enum.
greg7gkb

4
Đây là một kỹ thuật tốt khi bạn có một bảng liệt kê khá lớn và chỉ muốn ghi đè lên những thứ được in như cho một hoặc hai thành viên.
Donal Fellows

3
Điều này không có quy mô nào cả. Đừng làm điều này.
sebnukem

1
Điều này có ý nghĩa với tôi
hanzolo

35

Như Benny Neugebauer đề cập, bạn có thể ghi đè lên toString (). Tuy nhiên, thay vì ghi đè lên toString cho mỗi trường enum, tôi thích nhiều thứ như thế này:

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();
    }
}

Bạn cũng có thể thêm một phương thức tĩnh để truy xuất tất cả các trường, để in tất cả chúng, v.v. Chỉ cần gọi getValue để lấy chuỗi liên kết với từng mục 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;
 } 
}

bạn có thể thực hiện cuộc gọi như bên dưới bất cứ nơi nào bạn muốn nhận giá trị dưới dạng chuỗi từ enum.

Modes.MODE1.getvalue();

Điều này sẽ trả về "Mode1" dưới dạng Chuỗi.


6

Bạn có thể sử dụng Mode.mode1.name()tuy nhiên bạn thường không cần phải làm điều này.

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

6
Điều đáng chú ý là toán tử + sẽ gọi toString () trên enum và không đặt tên (). Và toString () có thể bị ghi đè để trả lại một cái gì đó ngoài tên (ngay cả khi điều đó không được mong muốn)
JB Nizet

1
Cả hai name()toString()có thể được ghi đè, nhưng hy vọng điều này sẽ rõ ràng từ việc đọc mã cho enumnếu điều này xảy ra.
Peter Lawrey

9
Tên số () là cuối cùng và luôn trả về tên của enum như được khai báo trong khai báo enum của nó.
JB Nizet

1
@JB Nizet, Bạn nói đúng. name()final. Cảm ơn bạn đã sửa chữa cho tôi. :)
Peter Lawrey

6

Theo tôi biết, cách duy nhất để có được tên là

Mode.mode1.name();

Nếu bạn thực sự cần nó theo cách này, tuy nhiên, bạn có thể làm:

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

    private String name;       

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

1
Nhưng trong trường hợp này, Mode.mode1vẫn không phải là loại String.
Larry

Ô đúng rồi. Bạn sẽ cần một phương thức getName (), loại đánh bại mục đích, vì vậy không, bạn không thể làm điều này.
Jake Roussel

"Tên" là tên trường xấu, nó là trường nổi bật của enum.
Wooff

6

Đối với enum của tôi, tôi không thực sự muốn nghĩ rằng chúng được phân bổ với 1 Chuỗi mỗi chuỗi. Đây là cách tôi triển khai phương thức toString () trên 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
Ném một ngoại lệ thời gian chạy sẽ tốt hơn thay vì trả về null vì nó không phải là mã không thể truy cập?
giá thuê

Điều returnnày là dư thừa, bởi vì bật enums với tất cả các enum đang chấm dứt.
Danon

5

Bạn chỉ có thể sử dụng:

""+ Modes.mode1

Tôi không chắc chắn 100% về điều này nhưng theo như hiểu biết của tôi thì diễn viên này không cần thiết, phải không? Kết hợp một chuỗi rỗng với một biến khác sẽ tự động gọi để chuyển đổi hoặc có bất kỳ ngoại lệ nào cho quy tắc này không?
Id không xác định

1
Bạn đã đúng, phiên bản chính xác nên được "" + Modes.mode1. Tôi đã sửa câu trả lời
Buddy

Câu trả lời của EB cũng có lợi khi gợi nhớ đến thành ngữ python ''.join()
anthropic android

5

giải pháp của tôi cho vấn đề của bạn!

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!");

    }
}

Có vẻ như vấn đề của OP đã được giải quyết 4 năm trước, nhưng chào mừng bạn đến với StackOverflow :)
TDG

1
Cảm ơn, chỉ để giúp ai đó như tôi, tìm kiếm câu trả lời khách quan hơn cho các vấn đề cũ :)
Renan Galdino da Silva

3

Enum chỉ là một lớp học đặc biệt một chút. Enums có thể lưu trữ các trường bổ sung, thực hiện các phương thức, v.v. Ví dụ

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

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

Bây giờ bạn có thể nói:

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

và xem đầu ra: 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
Bạn có thể vui lòng giải thích về cách nó sẽ giải quyết vấn đề?
Phani

bạn có thể gọi enum này ở bất cứ đâu bằng cách sử dụng dòng này: int id = 1; Chuỗi dayName = Days.getDay (id); , qua đây id. nó sẽ trả về Mô tả cho id đó là "Thứ ba"

2

Phương pháp này sẽ hoạt động với bất kỳ 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();

Nó sẽ in:

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

Thiết kế này cho hằng chuỗi enum hoạt động trong hầu hết các trường hợp.


0

sau nhiều lần thử tôi đã tìm ra giải pháp này

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

Bạn có thể thử điều này:

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

tôi thấy cái này dễ hơn để ngăn ngừa lỗi loại:

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

    String str;

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

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

tuy nhiên - điều này có thể hoạt động khi bạn cần sử dụng Chuỗi trên log / println hoặc bất cứ khi nào java tự động biên dịch phương thức toString (), nhưng trên một dòng mã như thế này ->

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

thay vì như đã đề cập ở trên, bạn vẫn sẽ phải gia hạn enum và sử dụng .name() trong những trường hợp như thế này:

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.