Сьогодні поговоримо про роботу з рядковими перерахуваннями, а конкретніше з
enum
класами, в яких організовано взаємодію з рядковими константами.
Використання рядкових перерахувань
Під час розробки програми періодично необхідно оперувати фіксованим набором рядкових значень. Це може бути будь що. Наприклад, список колірних кодів, що підтримуються програмою, або список пристроїв з якими здатна взаємодіяти наша програма, пори року і т.д. Усе це — зумовлений набір рядкових констант із загальною структурою, із якими необхідно налагодити програмне взаємодія лише на рівні 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
- локальне для розробки та дебагу
- Кожна URL-адресаа — це рядкова константа нашого переліку: вони визначаються в дужках у кожної
enum
константи. - Обов'язково наявність конструктора, який приймає аргумент того самого типу, що й кожна
enum
константа. - Область видимості конструктора -
private
абоpackage private
. - Необхідно визначити змінну — поле класу, яке зберігатиме певні строкові константи. Для цього поля необхідно створити метод геттер, щоб використовувати значення рядкових констант ззовні.
Перебір рядкових перерахувань
На цьому етапі ми можемо перебрати всі доступні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
вже на першій лекції п'ятого рівня .
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ