3
public enum Gender{

    m("male"), f("female");

    private final String value;

    private Gender(String option){
          value = option;
    }
}

文字列「男性」を列挙型に変換する方法を教えてください。はい、値は列挙型とは異なります。これは機能しません

 Gender.valueOf("male"); 

を提供することを考えていた.

1) for ループでパースする

また

2) Map を静的に初期化する

...

マップを初期化するときに、同じ文字列が存在すると実行時例外をスローできるため、2 番目の方法の方が優れていると感じています。

長所と短所は何ですか、または他のより良い解決策はありますか?

4

3 に答える 3

5

私は地図を使います:

public enum Gender {

    m("male"), f("female");

    private final String value;

    private static final Map<String, Gender> values = new HashMap<String, Gender>();
    static {
        for (Gender g : Gender.values()) {
            if (values.put(g.value, g) != null) {
                  throw new IllegalArgumentException("duplicate value: " + g.value);
            }
        }
    }

    private Gender(String option) {
          value = option;
    }

    public static Gender fromString(String option) {
        return values.get(option);
    }
}

これには、最初のアプローチよりも 2 つの利点があります。

  1. Genderこの方法では文字列を時間内に変換できますがO(1)、他の方法ではO(n)時間がかかります。
  2. これにより、重複する値が自動的に検出されます。
于 2013-03-07T13:38:47.640 に答える
2

これは、より一般化されたソリューションです。列挙型がコード値にマップされるときはいつでも使用します。たとえば、データベース テーブルにマップされる一連の離散値を列挙型で表す場合に特に役立ちます。定義されている次のいくつかの型は、一度だけ記述する必要があり、その後、任意の列挙型で使用できることに注意してください。

最初に、列挙型 (またはコレクションに格納される POJO) が実装するインターフェイスを定義します。

public interface Coded<T> {
    T getCode();
}

以下はGoogle Guavaを活用していますが、 Optionalクラスを使用するのではなく、null チェックを実行できます。

public final class CodedFinder {

    private CodedFinder() {}

    public static <V, T extends Enum<T> & Coded<V>> T find(final Class<T> target, final V code) {
        final Optional<T> found = findInternal(Arrays.asList(target.getEnumConstants()), code);
        if (! found.isPresent()) {
            throw new IllegalArgumentException(code.toString() + " is invalid for " + target.getSimpleName());
        }
        return found.get();
    }

    // Additional find methods for arrays and iterables redacted for clarity.

    private static <V, T extends Coded<V>> Optional<T> findInternal(final Iterable<T> values, final V code) {
        return Iterables.tryFind(values, CodedPredicate.of(code));
    }
}

上記のメソッドは、Class#getEnumConstantsを使用して、列挙型で定義されたすべての値を取得します。呼び出される実際の find メソッドは、列挙型だけでなく、配列やコレクションなどにも使用できます。

Guava の find メソッドを利用するにはPredicateを定義する必要があります。

public final class CodedPredicate<V, T extends Coded<V>> implements com.google.common.base.Predicate<T> {
    private final V value;

    private CodedPredicate(final V value) {
        this.value = value;
    }

    public static <V, T extends Coded<V>> CodedPredicate<V, T> of(final V value) {
        return new CodedPredicate<V, T>(value);
    }

    public boolean apply(final T current) {
        return value.equals(current.getCode());
    }
}

その述語は汎用的であるため、実用的な実装Coded<Integer>を持つその他の POJO を使用できますequals()

大量のコードのように見えますが、実際には上記で定義された 3 つの型のみがあり、これらは任意の数のプロジェクトで共有できます。値を検索するときはいつでも、簡単になります。

public final class GenderTest {

    @Test(groups="unit")
    public static void testValid() {

        assert CodedFinder.find(Gender.class, "male")  == Gender.m;
        assert CodedFinder.find(Gender.class, "female") == Gender.f;
    }

    @Test(groups="unit", expectedExceptions=IllegalArgumentException.class)
    public static void testInvalid() {

        CodedFinder.find(Gender.class, "foo");
    }

    public enum Gender implements Coded<String> {

        m("male"), f("female");

        private final String value;

        private Gender(final String option) {
              value = option;
        }

        public String getCode()
        {
            return value;
        }
    }
}
于 2013-03-07T14:06:47.873 に答える
0

私はこの状況に数回遭遇しましたが、通常は最初のアプローチを使用します。

public static Gender forValue(String value) {
    for (Gender gender : gender.values()) {
        if (gender.value.equals(value)) {
            return gender;
        }
    }

    return null; // or throw something like IllegalArgumentException 
}

あなたvalueが宣言されfinal、すべてのインスタンスをコードから宣言する必要があるため、値が一意であることに常に責任があるため、私にとっては問題はほとんどありません。

于 2013-03-07T13:39:48.303 に答える