Сегодня поговорим о работе со строковыми перечислениями, а конкретнее — с enum классами, в которых организовано взаимодействие со строковыми константами. Преобразование Enum в String - 1

Использование строковых перечислений

Во время разработки приложения периодически нужно оперировать фиксированным набором строковых значений. Это может быть что угодно. Например, список цветовых кодов, поддерживаемых приложением, или список устройств с которыми способно взаимодействовать наше приложение, времена года и т.д. Все это — предопределенный набор строковых констант с общей структурой, с которыми необходимо наладить программное взаимодействие на уровне Java кода. Когда необходимо взаимодействовать с предопределенным набором строковых (и не только) констант, лучшее решение — написать свой enum класс. Ниже рассмотрим примеры преобразования enum в string.

Создание строковых перечислений

Создадим enum класс, в котором хранится список различных окружений для развертывания приложения, а также URL каждого окружения:
public enum Environment {
    PROD("https://release.application.com/"),
    TEST("https://test.application.com/"),
    AUTO_TEST("https://autotest.application.com/"),
    DEV("http://localhost:8080");

    private final String url;

    Environment(String url) {
        this.url = url;
    }

    public String getUrl() {
        return url;
    }
}
В данном классе мы определили 4 окружения:
  • PROD — релизное
  • TEST — для ручного тестирования
  • AUTO_TEST — окружение для автотестов
  • DEV — локальное для разработки и дебага
А также 4 URL, для каждого из этих окружений. Давайте обратим внимание на некоторые важные моменты.
  1. Каждый URL — это строковая константа нашего перечисления: они определяются в скобках у каждой enum константы.
  2. Обязательно наличие конструктора, принимающего аргумент того же типа, что и каждая enum константа.
  3. Область видимости конструктора — private либо package private.
  4. Необходимо определить переменную — поле класса, которое будет хранить определенные нами строковые константы. Для этого поля необходимо создать метод геттер, чтобы использовать значения строковых констант извне.

Перебор строковых перечислений

На данном этапе мы уже можем перебрать все доступные enum значения, а также получить привязанные к ним строковые константы. Чтобы получить все значения любого enum класса, необходимо использовать метод values():
public class Main {
    public static void main(String[] args) {
        for (Environment env : Environment.values()) {
            System.out.println(env + " : " + env.getUrl());
        }
    }
}
Вывод:
PROD : https://release.application.com/
TEST : https://test.application.com/
AUTO_TEST : https://autotest.application.com/
DEV : http://localhost:8080
Как видно из примера, для вывода на печать имени enum константы мы передали ее в метод System.out.println, а для вывода на печать привязанного к данной константе url мы использовали определенный нами геттер.

Получение строковой константы из enum

Для получения значения любой строковой константы мы также можем вызывать геттер у любой enum константы:
public class Main {
    public static void main(String[] args) {

        String prodUrl = Environment.PROD.getUrl();
        String devUrl = Environment.DEV.getUrl();

        System.out.println("Production url is: " + prodUrl);
        System.out.println("Development url is: " + devUrl);

    }
}
Вывод:
Production url is: https://release.application.com/
Development url is: http://localhost:8080

Получение enum константы по имени

Порой бывает необходимо получить enum константу по ее строковому наименованию. Делается это с помощью метода valueOf(String), который возвращает константу по ее имени:
public class Main {
    public static void main(String[] args) {

        Environment prod = Environment.valueOf("PROD");
        Environment dev = Environment.valueOf("DEV");

        System.out.println("Production url is: " + prod.getUrl());
        System.out.println("Development url is: " + dev.getUrl());

    }
}
Вывод:
Production url is: https://release.application.com/
Development url is: http://localhost:8080
Но тут нужна осторожность. Если метод не найдет enum константу с указанным именем, будет брошено исключение java.lang.IllegalArgumentException.

Преобразование String в Enum

Иногда возникает обратная потребность. Зная значение enum, получить саму enum константу. Т.е. в нашем примере, зная определенный адрес, нужно получить соответствующую ему Environment константу. Есть несколько вариантов сделать это. И все они требуют доработки в самом enum классе. Вариант 1. Перебор внутри класса. Необходимо создать метод, который будет принимать строку, и сравнивать ее со всеми значениями enum класса. При совпадении метод будет возвращать нужное перечисление. Для нашего примера необходимо внутри класса Environment создать следующий метод:
public static Environment getEnvByUrl(String url) {
    for (Environment env : values()) {
        // либо equalsIgnoreCase, на ваше усмотрение
        if (env.getUrl().equals(url)) {
            return env;
        }
    }

    // Либо просто вернуть null
    throw new IllegalArgumentException("No enum found with url: [" + url + "]");
}
Тогда мы сможем получать enum из строки таким образом:
public class Main {
    public static void main(String[] args) {
        String url = "http://localhost:8080";
        Environment env = Environment.getEnvByUrl(url);

        System.out.println("Environment name for url=[" + url + "] is: " + env);
    }
}
Вывод:
Environment name for url=[http://localhost:8080] is: DEV
У этого подхода есть свои минусы. Каждый раз для получения enum константы придется перебирать все значения и производить некоторое количество сравнений. Ущерб производительности в таком случае будет определяться количеством констант и количеством подобных операций. У второго способа решения этой задачи такой проблемы нет. Полный код Enum класса:
public enum Environment {

    PROD("https://release.application.com/"),
    TEST("https://test.application.com/"),
    AUTO_TEST("https://autotest.application.com/"),
    DEV("http://localhost:8080");

    private final String url;

    Environment(String url) {
        this.url = url;
    }

    public String getUrl() {
        return url;
    }

    public static Environment getEnvByUrl(String url) {
        for (Environment env : values()) {
            if (env.getUrl().equals(url)) {
                return env;
            }
        }
        throw new IllegalArgumentException("No enum found with url: [" + url + "]");
    }
}
Вариант 2. Использование HashMap В этом случае мы создаем карту внутри нашего перечисления и заполняем ее один раз на этапе компиляции, а затем берем из нее значения:
public enum Environment {

    PROD("https://release.application.com/"),
    TEST("https://test.application.com/"),
    AUTO_TEST("https://autotest.application.com/"),
    DEV("http://localhost:8080");

    private final String url;

    Environment(String url) {
        this.url = url;
    }

    public String getUrl() {
        return url;
    }

    // Создаем static final карту
    private static final Map<String, Environment> LOOKUP_MAP = new HashMap<>();

    // Заполняем её всеми значениями
    static {
        for (Environment env : values()) {
            LOOKUP_MAP.put(env.getUrl(), env);
        }
    }

    // Возвращаем Environment по строковому url
    public static Environment getEnvByUrl(String url) {
        return LOOKUP_MAP.get(url);
    }
}
В плане использования оба варианта идентичны:
public class Main {
    public static void main(String[] args) {
        String url = "http://localhost:8080";
        Environment env = Environment.getEnvByUrl(url);

        System.out.println("Environment name for url=[" + url + "] is: " + env);
    }
}
Вывод:
Environment name for url=[http://localhost:8080] is: DEV
Но и у этого способа есть недостатки. Во-первых, кода стало значительно больше. А во-вторых, HashMap со всеми enum значениями будет храниться в памяти приложения постоянно. Как видим, у всего есть плюсы и минусы. Но учитывая то, что в enum классах обычно хранится не так уж много значений, минусы будут практически незаметны. Есть нюанс: если подобная операция (получение в Java Enum по String значению) выполняется часто, лучше использовать второй вариант. Подробнее с данной темой и Enum классами вообще можно познакомиться на курсе JavaRush. Студенты JavaRush изучают Enum уже на первой лекции пятого уровня. Преобразование Enum в String - 2