フィールド値に基づいて特定の列挙型を取得したいと思います。
列挙型:
public enum CrimeCategory {
ASBO ("Anti Social Behaviour"),
BURG ("Burglary"),
CRIMDAM ("Criminal Damage And Arson"),
DRUGS ("Drugs"),
OTHTHEFT ("Other Theft"),
PUPDISOR ("Public Disorder And Weapons"),
ROBBERY ("Robbery"),
SHOPLIF ("Shoplifting"),
VEHICLE ("Vehicle Crime"),
VIOLENT ("Violent Crime"),
OTHER ("Other Crime");
private String category;
private CrimeCategory (String category) {
this.category = category;
}
public String returnString() {
return category;
}
}
新しい列挙型の取得:
aStringRecivedFromJson = "Anti Social Behaviour"
CrimeCategory crimeCategoryEnum;
crimeCategoryEnum = CrimeCategory.valueOf(aStringRecivedFromJson);
私は、列挙型を元に戻して、他のHashMap
情報とともにCrime
に格納して渡すことができるようにする方法を模索してきました。
期待される結果:ASBO
参考までに、HashMapを使用した代替ソリューションを次に示します。
enum CrimeCategory {
ASBO("Anti Social Behaviour"),
BURG("Burglary"),
CRIMDAM("Criminal Damage And Arson"),
DRUGS("Drugs"),
OTHTHEFT("Other Theft"),
PUPDISOR("Public Disorder And Weapons"),
ROBBERY("Robbery"),
SHOPLIF("Shoplifting"),
VEHICLE("Vehicle Crime"),
VIOLENT("Violent Crime"),
OTHER("Other Crime");
private static final Map<String, CrimeCategory> map = new HashMap<>(values().length, 1);
static {
for (CrimeCategory c : values()) map.put(c.category, c);
}
private final String category;
private CrimeCategory(String category) {
this.category = category;
}
public static CrimeCategory of(String name) {
CrimeCategory result = map.get(name);
if (result == null) {
throw new IllegalArgumentException("Invalid category name: " + name);
}
return result;
}
}
静的メソッドをCrimeCategory
列挙型に追加します。
public static CrimeCategory valueOf(String name) {
for (CrimeCategory category : values()) {
if (category.category.equals(name)) {
return category;
}
}
throw new IllegalArgumentException(name);
}
インスタンスフィールドの値に基づいて列挙型定数を返す静的ファクトリメソッドは、他の回答で説明されている2つの形式のいずれかを取ります。列挙型値の反復に基づくソリューション、またはHashMap
に基づくソリューションです。 。
定数の数が少ない列挙型の場合、反復ソリューションはHashMap
ソリューションと同じくらいパフォーマンスが高い必要があります(ハッシュコードの計算、バケットとの照合、およびハッシュの衝突がないと仮定する必要があります) 。
列挙型が大きい場合、マップベースのソリューションのパフォーマンスが向上します(ただし、メモリにストレージスペースが必要です)。ただし、ファクトリメソッドが頻繁に呼び出されない場合は、マップを使用することによる全体的なパフォーマンスの向上は、計り知れないほど小さい可能性があります。
静的ファクトリメソッドに反復ルックアップまたはマップベースのルックアップを使用するかどうかの全体的な決定は、最終的には要件と環境によって異なります。プロファイリングで実際のパフォーマンスの問題が示された場合は、反復ルックアップから始めて、マップベースの実装に変更することは決して間違いではありません。
最後に、Java 8なので、Streams
APIは、マッピング用のパイプラインベースのソリューションを有効にします(反復ソリューションと同様のパフォーマンスが必要です)。たとえば、次のように言います。任意の列挙型クラスで使用できるインターフェイスを作成して、インスタンスフィールドの1つと一致する必要があるという意図を表現します。このインターフェイスをMatchable
と呼びましょう。このインターフェイスは、インスタンスフィールドを返すメソッドを定義します。一致させたいもの(例:getField()
)。このインターフェースは、実装している列挙型クラスから定数を返す静的ファクトリメソッドを定義することもできます。
_interface Matchable {
Object getField();
public static <E extends Enum<E> & Matchable> E forToken(Class<E> cls, Object token) {
return Stream.of(cls.getEnumConstants())
.filter(e -> e.getField().equals(token))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unknown token '" +
token + "' for enum " + cls.getName()));
}
}
_
これで、Matchable
を実装する定義済みの列挙型クラスは、Matchable.forToken()
静的ファクトリメソッドを使用して、インスタンスフィールド値が指定されたパラメータと一致する列挙型定数を見つけることができます。
ジェネリック型宣言_E extends Enum<E> & Matchable
_は、パラメーターとしてメソッドに渡される型トークンがMatchable
を実装する列挙型クラス用であることを保証します(そうでない場合、コードはコンパイルされません)。
アッシリアの答えは素晴らしいです。ファクトリメソッドからOptional
を返して、列挙型が見つからなかった場合の状況にクライアントが対処できるようにします(もちろん、この列挙型を内部で使用している場合は、IllegalArgumentException
をスローする方がよいでしょう。間違った引数でこのメソッドを呼び出すことは決して起こらないと思います-これはあなたの選択です)。
また、Map
を変更できないラッパーにラップして、列挙型内のどこかで誤って変更しないようにします(Map
は非公開ですが、後で新しい機能を追加するときに誰かが変更する可能性があります-少なくともそれについて考える力):
enum CrimeCategory {
ASBO("Anti Social Behaviour"),
BURG("Burglary"),
CRIMDAM("Criminal Damage And Arson"),
DRUGS("Drugs"),
OTHTHEFT("Other Theft"),
PUPDISOR("Public Disorder And Weapons"),
ROBBERY("Robbery"),
SHOPLIF("Shoplifting"),
VEHICLE("Vehicle Crime"),
VIOLENT("Violent Crime"),
OTHER("Other Crime");
private static final Map<String, CrimeCategory> MAP;
static {
Map<String, CrimeCategory> crimeCategoryMap = Arrays.stream(values())
.collect(toMap(cg -> cg.category, e -> e));
MAP = Collections.unmodifiableMap(crimeCategoryMap);
}
private final String category;
private CrimeCategory(String category) {
this.category = category;
}
public static Optional<CrimeCategory> of(final String name) {
return Optional.ofNullable(MAP.get(name));
}
}