Làm cách nào để có được giá trị enum từ giá trị chuỗi trong Java?


1984

Nói rằng tôi có một enum chỉ là

public enum Blah {
    A, B, C, D
}

và tôi muốn tìm giá trị enum của một chuỗi, ví dụ như "A"vậy Blah.A. Làm thế nào nó có thể làm điều này?

Enum.valueOf()phương pháp tôi cần? Nếu vậy, làm thế nào tôi sẽ sử dụng này?

Câu trả lời:


2258

Vâng, Blah.valueOf("A")sẽ cung cấp cho bạn Blah.A.

Lưu ý rằng tên phải là một kết hợp chính xác , bao gồm cả trường hợp: Blah.valueOf("a")Blah.valueOf("A ")cả hai ném một IllegalArgumentException.

Các phương thức tĩnh valueOf()values()được tạo tại thời gian biên dịch và không xuất hiện trong mã nguồn. Chúng xuất hiện trong Javadoc, mặc dù; ví dụ, Dialog.ModalityTypehiển thị cả hai phương thức


100
Để tham khảo, Blah.valueOf("A")phương pháp này phân biệt chữ hoa chữ thường và không dung thứ khoảng trắng bên ngoài, do đó, giải pháp thay thế được đề xuất dưới đây bởi @ JoséMi.
Brett

3
@Michael Myers, vì câu trả lời này được bình chọn nhiều nhất từ ​​trước đến nay, tôi có nên hiểu rằng đó là cách thực hành tốt để xác định enum và giá trị Chuỗi của nó giống hệt nhau không?
Kevin Meredith

4
@KevinMeredith: Nếu bạn có nghĩa là toString()giá trị, không, tôi sẽ không nói điều đó. name()sẽ cho bạn tên được xác định thực tế của hằng số enum trừ khi bạn ghi đè lên nó.
Michael Myers

3
Chính xác ý bạn là gì bởi "được tạo ra tại thời điểm biên dịch và không xuất hiện trong mã nguồn." ?
câyAreEverywhere

8
@treesAreEverywhere Cụ thể hơn, các phương thức đó được tạo ra (hoặc tổng hợp ) bởi trình biên dịch. enum Blah {...}Định nghĩa thực tế không nên cố gắng khai báo valuescũng không valuesOf. Nó giống như cách bạn có thể viết "AnyTypeName. Class" mặc dù bạn chưa bao giờ thực sự khai báo biến thành viên "class"; trình biên dịch làm cho tất cả chỉ hoạt động. (Câu trả lời này có thể không còn hữu ích với bạn 3 tháng sau, nhưng chỉ trong trường hợp.)
Ti Strga

864

Một giải pháp khác nếu văn bản không giống với giá trị liệt kê:

public enum Blah {
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;

    Blah(String text) {
        this.text = text;
    }

    public String getText() {
        return this.text;
    }

    public static Blah fromString(String text) {
        for (Blah b : Blah.values()) {
            if (b.text.equalsIgnoreCase(text)) {
                return b;
            }
        }
        return null;
    }
}

396
throw new IllegalArgumentException("No constant with text " + text + " found")sẽ là tốt hơn so với return null.
whiskeyierra

8
@whiskeysierra Jon Skeet sẽ không đồng ý với điều đó. stackoverflow.com/questions/1167982/
Mạnh

11
@Sangdol Bạn có thể khai sáng cho chúng tôi tại sao trả lại null tốt hơn không?
whiskeyierra

57
@Sangdol thường là một điều tốt để kiểm tra xem SUN - oops - Oracle đang làm gì trong tình huống tương tự. Và như Enum.valueOf () được hiển thị nó thực hành tốt nhất để ném một ngoại lệ trong trường hợp này. Bởi vì đó là một tình huống đặc biệt. "Tối ưu hóa hiệu suất" là một cái cớ tồi để viết mã không thể đọc được ;-)
raudi

5
Chà, bạn cũng có thể sử dụng chú thích @Nullable để làm cho nó "có thể đọc được" ;-)
JoséMi

121

Đây là một tiện ích tiện lợi tôi sử dụng:

/**
 * A common method for all enums since they can't have another base class
 * @param <T> Enum type
 * @param c enum type. All enums must be all caps.
 * @param string case insensitive
 * @return corresponding enum, or null
 */
public static <T extends Enum<T>> T getEnumFromString(Class<T> c, String string) {
    if( c != null && string != null ) {
        try {
            return Enum.valueOf(c, string.trim().toUpperCase());
        } catch(IllegalArgumentException ex) {
        }
    }
    return null;
}

Sau đó, trong lớp enum của tôi, tôi thường có điều này để lưu một số cách gõ:

public static MyEnum fromString(String name) {
    return getEnumFromString(MyEnum.class, name);
}

Nếu enum của bạn không phải là tất cả các mũ, chỉ cần thay đổi Enum.valueOfdòng.

Thật tệ, tôi không thể sử dụng T.classcho Enum.valueOfnhư Tbị xóa.


176
Đó là khối bắt trống thực sự khiến tôi thất vọng, xin lỗi.
whiskeyierra

32
@LazloBonin: Ngoại lệ dành cho các điều kiện đặc biệt, không dành cho luồng điều khiển. Nhận cho mình một bản sao Java hiệu quả .
Phục hồi Monica - M. Schröder

10
Nếu API Java mà bạn muốn sử dụng ném ngoại lệ và bạn không muốn mã của mình ném mã, bạn có thể nuốt ngoại lệ như thế này hoặc viết lại logic từ đầu để không có ngoại lệ nào được ném ở vị trí đầu tiên. Nuốt ngoại lệ thường là cái ác ít hơn.
Nate CK

47
Kinh khủng! Luôn luôn, luôn luôn bắt ngoại lệ nơi bạn có thể xử lý chúng. Ví dụ trên là một ví dụ hoàn hảo làm thế nào để KHÔNG làm điều đó . Tại sao? Vì vậy, nó trả về NULL và người gọi sau đó phải kiểm tra lại NULL hoặc ném NPE. Nếu người gọi biết cách xử lý tình huống thì thực hiện if vs try-Catch có thể trông thanh lịch hơn một chút, NHƯNG nếu anh ta không thể xử lý thì anh ta phải chuyển null và người gọi của người gọi lại phải kiểm tra lại NULL , vv vv
raudi

10
Để công bằng cho giải pháp ở trên, có những trường hợp thực sự sử dụng các trường hợp yêu cầu bạn trả về null thay vì ném IllegalArgumentException và phá vỡ luồng chương trình của bạn, ví dụ, ánh xạ enum giữa lược đồ dịch vụ web và lược đồ cơ sở dữ liệu trong đó chúng không phải luôn luôn là một -đến một. Tuy nhiên, tôi đồng ý rằng khối bắt không bao giờ được để trống. Đặt một số mã như log.warn hoặc một cái gì đó cho mục đích theo dõi.
Adrian M

101

Sử dụng mẫu từ Joshua Bloch, Java hiệu quả :

(đơn giản hóa cho ngắn gọn)

enum MyEnum {
    ENUM_1("A"),
    ENUM_2("B");

    private String name;

    private static final Map<String,MyEnum> ENUM_MAP;

    MyEnum (String name) {
        this.name = name;
    }

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

    // Build an immutable map of String name to enum pairs.
    // Any Map impl can be used.

    static {
        Map<String,MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
        for (MyEnum instance : MyEnum.values()) {
            map.put(instance.getName(),instance);
        }
        ENUM_MAP = Collections.unmodifiableMap(map);
    }

    public static MyEnum get (String name) {
        return ENUM_MAP.get(name);
    }
}

Cũng thấy:

Ví dụ Java Java sử dụng Enum và Bản đồ các thể hiện

Thứ tự thực hiện các khối tĩnh trong loại Enum

Làm cách nào tôi có thể tra cứu một enum Java từ giá trị Chuỗi của nó


4
Nếu Joshua Bloch nói thì đây là cách duy nhất để đi :-). Thật xấu hổ khi tôi luôn phải cuộn xuống đây.
dermoritz

11
Điều này thậm chí còn đơn giản hơn trong Java 8 như bạn có thể làm: Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))Tôi cũng khuyên bạn nên ghi đè toString () (được truyền qua hàm tạo) và sử dụng tên đó thay vì tên, đặc biệt là nếu Enum được liên kết với dữ liệu tuần tự hóa vì điều này cho phép bạn kiểm soát vỏ mà không đưa ra Sonar một phù hợp.
Novaterata

1
Java 8 chắc chắn có thể / sẽ thay đổi rất nhiều câu trả lời (tốt hơn) trên diễn đàn này. Không chắc chắn về việc bao giờ có đuôi (Sonar) vẫy chó (mã ứng dụng) mặc dù.
Darrell Teague

3
Nếu bạn định đặt nó vào một cách unmodifiableMapnào đó, thì không có lợi ích gì khi bắt đầu với a ConcurrentHashMap. Chỉ cần sử dụng một HashMap. (Nếu bạn có Guava ImmutableMapthì tôi khuyên bạn nên thay thế!)
Daniel Pryden

9
Khởi tạo tĩnh vốn đã được đồng bộ hóa , do đó, hoàn toàn không có lý do để sử dụng ConcurrentHashMapở đây, nơi bản đồ không bao giờ được sửa đổi sau khi khởi tạo. Do đó, tại sao ngay cả ví dụ trong chính JLS cũng sử dụng thông thường HashMap.
Radiodef

74

Bạn cũng nên cẩn thận với trường hợp của bạn. Hãy để tôi giải thích: làm Blah.valueOf("A")việc, nhưng Blah.valueOf("a")sẽ không làm việc. Sau đó, một lần nữa Blah.valueOf("a".toUpperCase(Locale.ENGLISH))sẽ làm việc.

chỉnh sửa
thay đổi toUpperCaseđể toUpperCase(Locale.ENGLISH)dựa trên tc. bình luận và các tài liệu java

chỉnh sửa2 Trên Android bạn nên sử dụng Locale.US, như sulai chỉ ra .


6
Hãy cảnh giác với miền địa phương mặc định!
tc.

3
Đối với những người dùng Android ngoài kia, tôi muốn chỉ ra rằng tài liệu Android rõ ràng khuyến khích việc sử dụng Locale.UScho đầu vào / đầu ra có thể đọc được của máy.
sulai

2
@Trengot Vâng, thật không may. Thổ Nhĩ Kỳ là một ví dụ tốt. Kết hợp điều này với việc xử lý các bộ ký tự mặc định của Java (mặc định là tiếng Latin trên Windows thay vì Unicode) và bạn sẽ thấy gần như không an toàn khi sử dụng các phiên bản mặc định của phương thức chấp nhận bộ ký tự hoặc ngôn ngữ. Bạn hầu như luôn luôn xác định rõ ràng chúng.
Stijn de Witt

Không chắc chắn các bộ ký tự "mặc định" của Java và "bị hỏng" mỗi lần nhưng được cấp, mặc định là UTF-8 thay cho các phần ghi đè (cần được thực hiện luôn rõ ràng) sẽ tạo ra các hệ thống tốt hơn cho các lập trình viên cơ sở thường không hiểu khái niệm bộ ký tự.
Darrell Teague

38

Đây là một phương pháp có thể làm điều đó cho bất kỳ Enum nào và không phân biệt chữ hoa chữ thường.

/** 
 * Finds the value of the given enumeration by name, case-insensitive. 
 * Throws an IllegalArgumentException if no match is found.  
 **/
public static <T extends Enum<T>> T valueOfIgnoreCase(
        Class<T> enumeration, String name) {

    for (T enumValue : enumeration.getEnumConstants()) {
        if (enumValue.name().equalsIgnoreCase(name)) {
            return enumValue;
        }
    }

    throw new IllegalArgumentException(String.format(
        "There is no value with name '%s' in Enum %s",
        name, enumeration.getName()
    ));
}

Biến thể này đang làm điều đó một cách chính xác: equalsIgnoreCaselà cách để đi. +1
Stijn de Witt

Giống như trường hợp không nhạy cảm nhưng ... thích Enums hơn (ngẫu nhiên) Các phép gán chuỗi cho các khóa và ... nhỏ nhưng lặp lại ít hiệu quả hơn cho việc tra cứu có thể lặp đi lặp lại như vậy. Do đó, hàm ý của EnumMap et al.
Darrell Teague

Điều này không hoạt động! Tôi đã thay đổi EqualsIgnoreCase thành bằng với mục đích của tôi. Mã không thành công mặc dù cả hai đầu vào bằng đều giống hệt nhau.
MasterJoe2

36

Sử dụng Blah.valueOf(string)là tốt nhất nhưng bạn cũng có thể sử dụng Enum.valueOf(Blah.class, string).


1
Trường hợp nhạy cảm, không giúp đỡ!
Murtaza Kanchwala

@MurtazaKanchwala Bạn có thể làm rõ nhận xét của mình không? Bạn đang cố làm gì vậy?
Peter Lawrey

2
Xin chào @PeterLawrey, tôi đã cố gắng tìm nạp Enum từ một chuỗi công khai enum ObjectType {PERSON ("Person") String StringNameName; ObjectType (StringameterName) {this.parameterName = tham sốName; } chuỗi công khai getParameterName () {return this.parameterName; } ObjectType tĩnh từString (StringameterName) {if (tham sốName! = null) {for (ObjectType objType: ObjectType.values ​​()) {if (tham số }}} trả về null; }}
Murtaza Kanchwala

34

Trong Java 8 trở lên, sử dụng Luồng :

public enum Blah
{
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;

    Blah(String text) {
        this.text = text;
    }

    public String getText() {
        return this.text;
    }

    public static Optional<Blah> fromText(String text) {
        return Arrays.stream(values())
          .filter(bl -> bl.text.equalsIgnoreCase(text))
          .findFirst();
    }
}

Không chắc chắn đây là một câu trả lời tốt hơn. Các luồng trong trường hợp này là một trình vòng lặp đơn luồng như bất kỳ giá trị nào khác trên tất cả các giá trị và được cho là ít hiệu suất hơn so với một tra cứu bản đồ. Các luồng có nhiều giá trị hơn trong ngữ cảnh đa luồng, ví dụ, thực thi song song tệp văn bản được phân tách bằng dòng mới có thể cải thiện hiệu suất.
Darrell Teague

28

Nếu bạn không muốn viết tiện ích của riêng mình, hãy sử dụng Google thư viện:

Enums.getIfPresent(Blah.class, "A")

Không giống như chức năng java tích hợp, nó cho phép bạn kiểm tra xem A có trong Blah không và không có ngoại lệ.


7
Điều đáng buồn là, điều này trả về một google Tùy chọn và không phải java Tùy chọn
javaProgrammer 19/8/2016

Thật. Mặc dù vậy. Google và Netflix có libs Java tuyệt vời. Khi có sự chồng chéo với các lớp bắt kịp Java được triển khai trong các phiên bản mới hơn chắc chắn gây ra sự cố. Loại phải có tất cả trong một lib nhà cung cấp.
Darrell Teague

26

2 xu của tôi ở đây: sử dụng Luồng Java8 + kiểm tra một chuỗi chính xác:

public enum MyEnum {
    VALUE_1("Super"),
    VALUE_2("Rainbow"),
    VALUE_3("Dash"),
    VALUE_3("Rocks");

    private final String value;

    MyEnum(String value) {
        this.value = value;
    }

    /**
     * @return the Enum representation for the given string.
     * @throws IllegalArgumentException if unknown string.
     */
    public static MyEnum fromString(String s) throws IllegalArgumentException {
        return Arrays.stream(MyEnum.values())
                .filter(v -> v.value.equals(s))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("unknown value: " + s));
    }
}

** BIÊN TẬP **

Đổi tên hàm thành fromString()từ khi đặt tên cho nó bằng cách sử dụng quy ước đó, bạn sẽ nhận được một số lợi ích từ chính ngôn ngữ Java; ví dụ:

  1. Chuyển đổi trực tiếp các loại tại chú thích HeaderParam

1
Ngoài ra, để cho phép bạn viết switchcác khối dễ đọc hơn , bạn có thể .orElse(null)thay vì .orElseThrow()đó để bạn có thể viết mã ném ngoại lệ trong defaultmệnh đề - và bao gồm thông tin hữu ích hơn khi được yêu cầu. Và để làm cho nó dễ dàng hơn bạn có thể sử dụngv -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Adam

hoặc chỉ cần trả lại Optionaltừ findFirst(), cho phép người dùng quyết định nếu anh ta muốn .orElse(null), orElseThrow()hoặc bất cứ điều gì ....
user85421

1
Khai báo a public static MyEnum valueOf(String)thực sự là một lỗi biên dịch, vì nó giống như lỗi được định nghĩa ngầm, vì vậy phiên bản cũ hơn của câu trả lời của bạn thực sự tốt hơn. ( jls , ideone )
Radiodef 23/12/18

Trong tùy chọn của tôi, tốt hơn là tránh Ngoại lệ và sử dụng Tùy chọn. Bên cạnh đó, chúng ta nên hủy null và sử dụng Tùy chọn thay thế.
Hans Schreuder

Một lần nữa, chỉ cần nhớ rằng ngay cả khi mã tìm kiếm ít hơn hoặc tốt hơn ... thì việc triển khai Luồng như thế này chỉ là một trình vòng lặp trên tất cả các giá trị so với tra cứu bản đồ (ít hiệu suất hơn).
Darrell Teague

16

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

public enum ObjectType {
    PERSON("Person");

    public String parameterName;

    ObjectType(String parameterName) {
        this.parameterName = parameterName;
    }

    public String getParameterName() {
        return this.parameterName;
    }

    //From String method will return you the Enum for the provided input string
    public static ObjectType fromString(String parameterName) {
        if (parameterName != null) {
            for (ObjectType objType : ObjectType.values()) {
                if (parameterName.equalsIgnoreCase(objType.parameterName)) {
                    return objType;
                }
            }
        }
        return null;
    }
}

Thêm một bổ sung:

   public static String fromEnumName(String parameterName) {
        if (parameterName != null) {
            for (DQJ objType : DQJ.values()) {
                if (parameterName.equalsIgnoreCase(objType.name())) {
                    return objType.parameterName;
                }
            }
        }
        return null;
    }

Điều này sẽ trả về cho bạn Giá trị theo Tên Enum được xâu chuỗi Ví dụ: nếu bạn cung cấp "PERSON" trong fromEnumName, nó sẽ trả về cho bạn Giá trị của Enum tức là "Người"


13

Một cách khác để làm điều này bằng cách sử dụng phương thức tĩnh ẩn name()của Enum. Tên sẽ trả về chuỗi chính xác được sử dụng để tạo enum có thể được sử dụng để kiểm tra đối với chuỗi được cung cấp:

public enum Blah {

    A, B, C, D;

    public static Blah getEnum(String s){
        if(A.name().equals(s)){
            return A;
        }else if(B.name().equals(s)){
            return B;
        }else if(C.name().equals(s)){
            return C;
        }else if (D.name().equals(s)){
            return D;
        }
        throw new IllegalArgumentException("No Enum specified for this string");
    }
}

Kiểm tra:

System.out.println(Blah.getEnum("B").name());

//it will print B  B

nguồn cảm hứng: 10 ví dụ về Enum trong Java


7
Đây thực chất là những gì valueOflàm cho bạn. Phương pháp tĩnh này không cung cấp thêm bất cứ điều gì, ngoại trừ et tất cả. Sau đó, các cấu trúc if / other rất nguy hiểm ... bất kỳ hằng số enum mới nào được thêm vào sẽ khiến phương thức này bị phá vỡ mà không thay đổi.
YoYo

Cũng xem xét ví dụ này về cách chúng tôi có thể sử dụng valueOf để thực hiện tra cứu không nhạy cảm trường hợp hoặc làm thế nào chúng tôi có thể tránh ngoại lệ và sử dụng bí danh để cung cấp tên thay thế: stackoverflow.com/a/12659023/744133
YoYo

2
name()không tĩnh.
nrubin29

10

Giải pháp sử dụng thư viện Guava. Phương thức getPlanet () không phân biệt chữ hoa chữ thường, vì vậy getPlanet ("MerCUrY") sẽ trả về Planet.MERCURY.

package com.universe.solarsystem.planets;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Enums;
import com.google.common.base.Optional;

//Pluto and Eris are dwarf planets, who cares!
public enum Planet {
   MERCURY,
   VENUS,
   EARTH,
   MARS,
   JUPITER,
   SATURN,
   URANUS,
   NEPTUNE;

   public static Planet getPlanet(String name) {
      String val = StringUtils.trimToEmpty(name).toUpperCase();
      Optional <Planet> possible = Enums.getIfPresent(Planet.class, val);
      if (!possible.isPresent()) {
         throw new IllegalArgumentException(val + "? There is no such planet!");
      }
      return possible.get();
   }
}

8

Để thêm vào các câu trả lời trước đó và giải quyết một số cuộc thảo luận xung quanh null và NPE tôi đang sử dụng Tùy chọn Guava để xử lý các trường hợp vắng mặt / không hợp lệ. Điều này hoạt động rất tốt cho phân tích cú pháp URI / tham số.

public enum E {
    A,B,C;
    public static Optional<E> fromString(String s) {
        try {
            return Optional.of(E.valueOf(s.toUpperCase()));
        } catch (IllegalArgumentException|NullPointerException e) {
            return Optional.absent();
        }
    }
}

Đối với những người không biết, đây là một số thông tin khác về cách tránh null với Tùy chọn: https://code.google.com.vn/p/guava-lologists/wiki/UsingAndAvoidingNullExplained#Optional


Đây là một câu trả lời thực sự tốt cho các mẫu liên quan và sử dụng Tùy chọn bên trong Enum - thúc đẩy thực tế rằng Enums cũng là các lớp và do đó có thể được trang trí bằng các phương thức, phương thức ghi đè, v.v. null được trả về từ các phương thức làm cho cấu trúc đó bị lỗi (NPE ở những nơi không xác định trong chuỗi các cuộc gọi phương thức Fluent).
Darrell Teague

8

Trong Java 8, mẫu Bản đồ tĩnh thậm chí còn dễ dàng hơn và là phương thức được ưu tiên của tôi. Nếu bạn muốn sử dụng Enum với Jackson, bạn có thể ghi đè lênString và sử dụng tên đó thay vì tên, sau đó chú thích bằng@JsonValue

public enum MyEnum {
    BAR,
    BAZ;
    private static final Map<String, MyEnum> MAP = Stream.of(MyEnum.values()).collect(Collectors.toMap(Enum::name, Function.identity()));
    public static MyEnum fromName(String name){
        return MAP.get(name);
    }
}

public enum MyEnumForJson {
    BAR("bar"),
    BAZ("baz");
    private static final Map<String, MyEnumForJson> MAP = Stream.of(MyEnumForJson.values()).collect(Collectors.toMap(Object::toString, Function.identity()));
    private final String value;

    MyEnumForJson(String value) {
        this.value = value;
    }

    @JsonValue
    @Override
    public String toString() {
        return value;
    }

    public static MyEnumForJson fromValue(String value){
        return MAP.get(value);
    }
}

Jackson là một triển khai JSON (Ký hiệu đối tượng JavaScript). Câu hỏi ban đầu không liên quan gì đến JSON.
Darrell Teague

Phần JSON chỉ là phần thưởng mà tôi thấy có liên quan vào thời điểm đó, vì nhận được Enum từ một chuỗi về cơ bản là một loại giải tuần tự hóa và JSON / Jackson có lẽ là giải pháp tuần tự hóa phổ biến nhất.
Novaterata

Hiểu nhưng từ khía cạnh kiểm duyệt - nó không góp phần trả lời câu hỏi của OP nên chỉ cố gắng giúp đặt bối cảnh ở đó. Thực sự, đây là cách để chuyển đổi các đối tượng thành dạng chính tắc trong Java với Jackson là một thư viện tuyệt vời.
Darrell Teague

6
public static MyEnum getFromValue(String value) {
    MyEnum resp = null;
    MyEnum nodes[] = values();
    for(int i = 0; i < nodes.length; i++) {
        if(nodes[i].value.equals(value)) {
            resp = nodes[i];
            break;
        }
    }
    return resp;
}

hãy xem liên kết này để được hướng dẫn trả lời và đặt câu hỏi trên stackoverflow.com: stackoverflow.com/faq
bakoyaro

1
Điều đó ít nhiều giống với câu trả lời của JoseMi
Rup

6

Phương pháp O (1) lấy cảm hứng từ mã được tạo tiết kiệm sử dụng hàm băm.

public enum USER {
        STUDENT("jon",0),TEACHER("tom",1);

        private static final Map<String, Integer> map = new HashMap<>();

        static {
                for (USER user : EnumSet.allOf(USER.class)) {
                        map.put(user.getTypeName(), user.getIndex());
                }
        }

        public static int findIndexByTypeName(String typeName) {
                return map.get(typeName);
        }

        private USER(String typeName,int index){
                this.typeName = typeName;
                this.index = index;
        }
        private String typeName;
        private int index;
        public String getTypeName() {
                return typeName;
        }
        public void setTypeName(String typeName) {
                this.typeName = typeName;
        }
        public int getIndex() {
                return index;
        }
        public void setIndex(int index) {
                this.index = index;
        }

}

Lưu ý các số nhận dạng 0 (0) và một (1) là không cần thiết. Phương thức Enum value () sẽ trả về các thành viên theo cùng thứ tự như được mã hóa. Do đó, mục đầu tiên sẽ là số 0, mục thứ hai, v.v.
Darrell Teague

6

Enum rất hữu ích, tôi đã sử dụng Enumrất nhiều để thêm mô tả cho một số trường bằng các ngôn ngữ khác nhau, như ví dụ sau:

public enum Status {

    ACT(new String[] { "Accepted", "مقبول" }),
    REJ(new String[] { "Rejected", "مرفوض" }),
    PND(new String[] { "Pending", "في الانتظار" }),
    ERR(new String[] { "Error", "خطأ" }),
    SNT(new String[] { "Sent", "أرسلت" });

    private String[] status;

    public String getDescription(String lang) {
        return lang.equals("en") ? status[0] : status[1];
    }

    Status(String[] status) {
        this.status = status;
    }
}

Và sau đó, bạn có thể truy xuất mô tả một cách linh hoạt dựa trên mã ngôn ngữ được truyền cho getDescription(String lang)phương thức, ví dụ:

String statusDescription = Status.valueOf("ACT").getDescription("en");

1
Ví dụ tốt với việc đẩy Enums hơn nữa. Sẽ thực hiện mã hóa ngôn ngữ bằng cách sử dụng tên tĩnh và tra cứu tiêu chuẩn trong Bản đồ nhưng vẫn ... một ví dụ điển hình về việc có một enum với các thẻ khác nhau cho những gì về cơ bản có cùng giá trị logic.
Darrell Teague

5

Thế còn?

public enum MyEnum {
    FIRST,
    SECOND,
    THIRD;

    public static Optional<MyEnum> fromString(String value){
        try{
            return Optional.of(MyEnum.valueOf(value));
        }catch(Exception e){
            return Optional.empty();
        }
    }
}

4

java.lang.Enum định nghĩa một số phương thức hữu ích, có sẵn cho tất cả các kiểu liệt kê trong Java:

  • Bạn có thể sử dụng name()phương thức để lấy tên của bất kỳ hằng số Enum nào. Chuỗi ký tự được sử dụng để viết hằng enum là tên của họ.
  • values()Phương pháp tương tự có thể được sử dụng để lấy một mảng của tất cả các hằng số Enum từ một loại Enum.
  • Và đối với câu hỏi được hỏi, bạn có thể sử dụng valueOf()phương thức để chuyển đổi bất kỳ Chuỗi nào thành hằng số Enum trong Java, như được hiển thị bên dưới.
public class EnumDemo06 {
    public static void main(String args[]) {
        Gender fromString = Gender.valueOf("MALE");
        System.out.println("Gender.MALE.name() : " + fromString.name());
    }

    private enum Gender {
        MALE, FEMALE;
    }
}

Output:
Gender.MALE.name() : MALE

Trong đoạn mã này, valueOf()phương thức trả về một Enum hằng giới tính.MALE, gọi tên trên trả về đó "MALE".


4

Thư viện commons-lang của Apache có hàm tĩnh org.apache.commons.lang3.EnumUtils.getEnum sẽ ánh xạ một Chuỗi thành loại Enum của bạn. Câu trả lời tương tự về cơ bản là Geoffreys nhưng tại sao lại tự lăn lộn khi nó ở ngoài tự nhiên.


1
Nhận xét công bằng (DRY) nhưng ... trong khi hầu hết các công cụ của Apache Commons đều tuyệt vời, tôi đã tìm thấy một số lỗi và bản thân chống mẫu trong cơ sở đó. Do đó, đề cập đến việc thực hiện Joshua Bloch có thể là bước đi mạnh mẽ hơn. Sau đó phải xem lại mã Apache để biết ai đó đã triển khai. Nếu người ta nói Doug Leah nổi tiếng đã viết lại đồng thời Java ... thì tôi sẽ tin tưởng nó hoàn toàn.
Darrell Teague

4

Thêm vào câu trả lời được xếp hạng hàng đầu, với một tiện ích hữu ích ...

valueOf() đưa ra hai trường hợp ngoại lệ khác nhau trong trường hợp không thích đầu vào của nó.

  • IllegalArgumentException
  • NullPointerExeption

Nếu các yêu cầu của bạn là như vậy mà bạn không có bất kỳ đảm bảo nào rằng Chuỗi của bạn chắc chắn sẽ khớp với giá trị enum, ví dụ: nếu dữ liệu Chuỗi đến từ cơ sở dữ liệu và có thể chứa phiên bản cũ của enum, thì bạn sẽ cần xử lý các thường ...

Vì vậy, đây là một phương thức có thể sử dụng lại mà tôi đã viết cho phép chúng ta xác định Enum mặc định được trả về nếu Chuỗi chúng ta vượt qua không khớp.

private static <T extends Enum<T>> T valueOf( String name , T defaultVal) {
        try {
            return Enum.valueOf(defaultVal.getDeclaringClass() , name);
        } catch (IllegalArgumentException | NullPointerException e) {
            return defaultVal;
        }
    }

Sử dụng nó như thế này:

public enum MYTHINGS {
    THINGONE,
    THINGTWO
}

public static void main(String [] asd) {
  valueOf("THINGTWO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGTWO
  valueOf("THINGZERO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGONE
}

2

Vì một sự đảo ngược switchchưa được đề cập nhưng tôi giới thiệu nó (sử dụng lại enum của OP):

  private enum Blah {
    A, B, C, D;

    public static Blah byName(String name) {
      switch (name) {
        case "A":
          return A;
        case "B":
          return B;
        case "C":
          return C;
        case "D":
          return D;
        default:
          throw new IllegalArgumentException(
            "No enum constant " + Blah.class.getCanonicalName() + "." + name);
      }
    }
  }

Vì điều này không cung cấp bất kỳ giá trị bổ sung nào cho valueOf(String name)phương thức, nên việc xác định một phương thức bổ sung nếu chúng ta muốn có một hành vi khác là điều hợp lý. Nếu chúng tôi không muốn nâng cao, IllegalArgumentExceptionchúng tôi có thể thay đổi việc triển khai thành:

  private enum Blah {
    A, B, C, D;

    public static Blah valueOfOrDefault(String name, Blah defaultValue) {
      switch (name) {
        case "A":
          return A;
        case "B":
          return B;
        case "C":
          return C;
        case "D":
          return D;
        default:
          if (defaultValue == null) {
            throw new NullPointerException();
          }
          return defaultValue;
      }
    }
  }

Bằng cách cung cấp một giá trị mặc định chúng tôi giữ hợp đồng của Enum.valueOf(String name)không ném một IllegalArgumentException theo cách mà rằng trong mọi trường hợp không nullđược trả lại. Vì vậy, chúng tôi ném một NullPointerExceptionnếu tên là nullvà trong trường hợp defaultnếu defaultValuenull. Đó là cách làm valueOfOrDefaultviệc.

Cách tiếp cận này thông qua thiết kế của Map-Interface cung cấp một phương thức Map.getOrDefault(Object key, V defaultValue)như Java 8.


1

Một tiện ích khác chụp theo cách ngược lại. Sử dụng một giá trị xác định Enum đó, không phải từ tên của nó.

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.EnumSet;

public class EnumUtil {

    /**
     * Returns the <code>Enum</code> of type <code>enumType</code> whose a 
     * public method return value of this Enum is 
     * equal to <code>valor</code>.<br/>
     * Such method should be unique public, not final and static method 
     * declared in Enum.
     * In case of more than one method in match those conditions
     * its first one will be chosen.
     * 
     * @param enumType
     * @param value
     * @return 
     */
    public static <E extends Enum<E>> E from(Class<E> enumType, Object value) {
        String methodName = getMethodIdentifier(enumType);
        return from(enumType, value, methodName);
    }

    /**
     * Returns the <code>Enum</code> of type <code>enumType</code> whose  
     * public method <code>methodName</code> return is 
     * equal to <code>value</code>.<br/>
     *
     * @param enumType
     * @param value
     * @param methodName
     * @return
     */
    public static <E extends Enum<E>> E from(Class<E> enumType, Object value, String methodName) {
        EnumSet<E> enumSet = EnumSet.allOf(enumType);
        for (E en : enumSet) {
            try {
                String invoke = enumType.getMethod(methodName).invoke(en).toString();
                if (invoke.equals(value.toString())) {
                    return en;
                }
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    private static String getMethodIdentifier(Class<?> enumType) {
        Method[] methods = enumType.getDeclaredMethods();
        String name = null;
        for (Method method : methods) {
            int mod = method.getModifiers();
            if (Modifier.isPublic(mod) && !Modifier.isStatic(mod) && !Modifier.isFinal(mod)) {
                name = method.getName();
                break;
            }
        }
        return name;
    }
}

Thí dụ:

public enum Foo {
    ONE("eins"), TWO("zwei"), THREE("drei");

    private String value;

    private Foo(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

EnumUtil.from(Foo.class, "drei")trả về Foo.THREE, bởi vì nó sẽ sử dụng getValueđể khớp với "drei", là phương thức công khai duy nhất, không phải là phương thức cuối cùng và không tĩnh trong Foo. Trong trường hợp Foo có nhiều hơn phương thức công khai, không phải cuối cùng và không tĩnh, ví dụ, getTranslatetrả về "drei", phương thức khác có thể được sử dụng : EnumUtil.from(Foo.class, "drei", "getTranslate").


1

Giải pháp Kotlin

Tạo một phần mở rộng và sau đó gọi valueOf<MyEnum>("value"). Nếu loại không hợp lệ, bạn sẽ nhận được null và phải xử lý nó

inline fun <reified T : Enum<T>> valueOf(type: String): T? {
    return try {
        java.lang.Enum.valueOf(T::class.java, type)
    } catch (e: Exception) {
        null
    }
}

Ngoài ra, bạn có thể đặt giá trị mặc định, gọi valueOf<MyEnum>("value", MyEnum.FALLBACK)và tránh phản hồi null. Bạn có thể mở rộng enum cụ thể của mình để mặc định là tự động

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T {
    return try {
        java.lang.Enum.valueOf(T::class.java, type)
    } catch (e: Exception) {
        default
    }
}

Hoặc nếu bạn muốn cả hai, hãy tạo cái thứ hai:

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default

Bạn có nghĩ rằng câu trả lời của bạn sẽ có một ngôi nhà tốt hơn ở đây? stackoverflow.com/questions/28548015/ từ
nabster

0

Tôi thích sử dụng loại quy trình này để phân tích các lệnh dưới dạng chuỗi thành liệt kê. Tôi thường có một trong những bảng liệt kê là "không xác định" vì vậy sẽ giúp trả lại khi không tìm thấy những thứ khác (ngay cả trên cơ sở không nhạy cảm) chứ không phải là null (nghĩa là không có giá trị). Do đó tôi sử dụng phương pháp này.

static <E extends Enum<E>> Enum getEnumValue(String what, Class<E> enumClass) {
    Enum<E> unknown=null;
    for (Enum<E> enumVal: enumClass.getEnumConstants()) {  
        if (what.compareToIgnoreCase(enumVal.name()) == 0) {
            return enumVal;
        }
        if (enumVal.name().compareToIgnoreCase("unknown") == 0) {
            unknown=enumVal;
        }
    }  
    return unknown;
}

-1

Cách nhanh nhất để có được tên của enum là tạo một bản đồ văn bản enum và giá trị khi ứng dụng bắt đầu và để có được tên gọi hàm Blah.getEnumName ():

public enum Blah {
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;
    private HashMap<String, String> map;
    Blah(String text) {
    this.text = text;
    }

    public String getText() {
      return this.text;
    }

    static{
      createMapOfTextAndName();
    }

    public static void createMapOfTextAndName() {
        map = new HashMap<String, String>();
        for (Blah b : Blah.values()) {
             map.put(b.getText(),b.name());
        }
    }
    public static String getEnumName(String text) {
        return map.get(text.toLowerCase());
    } 
}
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.