Могу ли я получить перечисление, основанное на значении его поля?

Я хочу получить конкретное перечисление, основанное на его значении поля.

Enum:

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

Ответы

Ответ 1

Для справки, вот альтернативное решение с 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;
  }
}

Ответ 2

Добавить статический метод в перечисление CrimeCategory:

public static CrimeCategory valueOf(String name) {
    for (CrimeCategory category : values()) {
        if (category.category.equals(name)) {
            return category;
        }
    }    
    throw new IllegalArgumentException(name);
}

Ответ 3

Статические методы factory, которые возвращают константу enum, основанную на значении поля экземпляра, принимают одну из двух форм, описанных в других ответах: решение на основе итерации значений перечисления или решение на основе a HashMap.

Для перечислений с небольшим числом констант итеративное решение должно быть таким же эффективным, как решение HashMap (которое требует вычисления хэш-кода, сопоставления его с ведром и предполагая, что не будет никаких хэш-коллизий).

Для больших перечислений решение на основе карты будет более эффективным (но для хранения требуется место для хранения в памяти). Однако, если метод factory вызывается нечасто, тогда общее улучшение производительности с помощью карты может быть неизмеримо малым.

Общее решение использовать итеративный поиск или поиск на основе карты для статического метода factory в конечном итоге будет зависеть от ваших требований и среды. Неправильно начинать с итеративного поиска, а затем изменять реализацию на основе карты, если профилирование показывает фактическую проблему с производительностью.

Наконец, начиная с Java 8 API Streams позволяет использовать конвейерное решение для сопоставления (которое должно иметь производительность, аналогичную итеративному решению). Например, скажите, что вы хотите создать интерфейс, который вы можете использовать для любого класса enum, чтобы выразить свое намерение, чтобы оно соответствовало одному из его полей экземпляра. Позвоните по этому интерфейсу Matchable. Этот интерфейс определяет метод, который возвращает поле экземпляра, по которому вы хотите сопоставить (например, getField()). Этот интерфейс также может определять статический метод factory для возврата константы из любого реализующего класса перечисления:

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

Теперь любой класс enum, который вы определяете, реализующий Matchable, может использовать статический factory метод Matchable.forToken() для поиска константы перечисления, значение поля экземпляра которой соответствует предоставленному параметру.

Объявление типового типа E extends Enum<E> & Matchable гарантирует, что маркер типа, переданный методу в качестве параметра, будет для класса enum, который реализует Matchable (иначе код не будет компилироваться).