Avatar ·

Как получить значение enum из строки в Java?

Всем привет! Я новичок в Java и столкнулся с проблемой при работе с перечислениями (enum). У меня есть enum, который описывает статусы заказа: ```java public enum OrderStatus { NEW, PROCESSING, SHIPPED, DELIVERED, CANCELLED } ``` Я получаю строку от пользователя через консоль или из базы данных, например "PROCESSING" или "processing". Мне нужно преобразовать эту строку в соответствующее значение enum, чтобы использовать его в логике приложения. Проблема в том, что я не знаю, как правильно это сделать. Я пробовал просто присвоить строку переменной типа OrderStatus, но компилятор выдаёт ошибку. Я слышал, что есть метод valueOf(), но он выбрасывает исключение, если строка не совпадает с именем константы. А что если строка написана в другом регистре? Или содержит пробелы? Как правильно обработать такие случаи? Подскажите, пожалуйста, как в Java получить значение enum из строки, чтобы это было надёжно и безопасно? Желательно с примерами кода. Заранее спасибо за помощь! <<>>

Решение: метод valueOf() и обработка исключений

Самый простой и встроенный способ получить значение enum из строки — использовать метод valueOf(String), который автоматически генерируется для каждого enum в Java. Однако этот метод чувствителен к регистру и выбрасывает IllegalArgumentException, если строка не соответствует ни одной константе.

public enum OrderStatus {
    NEW,
    PROCESSING,
    SHIPPED,
    DELIVERED,
    CANCELLED
}

// Использование
String input = "PROCESSING";
OrderStatus status = OrderStatus.valueOf(input); // Работает

String badInput = "processing"; // Нижний регистр
OrderStatus status2 = OrderStatus.valueOf(badInput); // Выбросит IllegalArgumentException

Безопасный способ с обработкой регистра

Чтобы сделать код устойчивым к разному регистру, можно преобразовать входную строку к верхнему регистру перед вызовом valueOf():

public static OrderStatus fromString(String input) {
    if (input == null) {
        throw new IllegalArgumentException("Строка не может быть null");
    }
    return OrderStatus.valueOf(input.toUpperCase());
}

Добавление собственного поля и метода

Если вам нужно сопоставлять строки, которые отличаются от имён констант (например, с пробелами или другими значениями), лучше добавить в enum поле и метод для поиска:

public enum OrderStatus {
    NEW("новый"),
    PROCESSING("в обработке"),
    SHIPPED("отправлен"),
    DELIVERED("доставлен"),
    CANCELLED("отменён");

    private final String displayName;

    OrderStatus(String displayName) {
        this.displayName = displayName;
    }

    public String getDisplayName() {
        return displayName;
    }

    // Поиск по displayName (регистронезависимый)
    public static OrderStatus fromDisplayName(String displayName) {
        for (OrderStatus status : OrderStatus.values()) {
            if (status.displayName.equalsIgnoreCase(displayName)) {
                return status;
            }
        }
        throw new IllegalArgumentException("Неизвестный статус: " + displayName);
    }

    // Поиск по имени константы (регистронезависимый)
    public static OrderStatus fromName(String name) {
        for (OrderStatus status : OrderStatus.values()) {
            if (status.name().equalsIgnoreCase(name)) {
                return status;
            }
        }
        throw new IllegalArgumentException("Неизвестное имя: " + name);
    }
}

Использование Optional для безопасного поиска

С Java 8 можно использовать Optional, чтобы избежать исключений и вернуть пустое значение, если строка не найдена:

import java.util.Optional;

public static Optional<OrderStatus> findStatus(String input) {
    if (input == null) return Optional.empty();
    
    for (OrderStatus status : OrderStatus.values()) {
        if (status.name().equalsIgnoreCase(input.trim())) {
            return Optional.of(status);
        }
    }
    return Optional.empty();
}

// Использование
String userInput = "  shipped  ";
Optional<OrderStatus> statusOpt = findStatus(userInput);
statusOpt.ifPresent(s -> System.out.println("Найден статус: " + s));

Рекомендации

  • Всегда проверяйте входную строку на null и пустые значения
  • Используйте trim() для удаления лишних пробелов
  • Для критичных к производительности мест (например, обработка тысяч запросов) можно создать статический HashMap для быстрого поиска
  • Рассмотрите использование Enum.valueOf() только если вы полностью контролируете входные данные

Выберите подход, который лучше всего подходит для вашей задачи. Для простых случаев достаточно valueOf() с преобразованием регистра, для более сложных сопоставлений — добавляйте кастомные поля и методы поиска.

<<>>

Альтернативный подход: использование HashMap для быстрого поиска

Если ваш enum содержит много констант и вам нужна максимальная производительность при частых запросах, используйте статический HashMap. Этот подход особенно полезен, когда строки-ключи отличаются от имён констант.

import java.util.HashMap;
import java.util.Map;

public enum HttpStatus {
    OK(200, "OK"),
    NOT_FOUND(404, "Not Found"),
    INTERNAL_SERVER_ERROR(500, "Internal Server Error");

    private final int code;
    private final String description;
    private static final Map<String, HttpStatus> LOOKUP_MAP = new HashMap<>();

    static {
        for (HttpStatus status : HttpStatus.values()) {
            // Ключ — код или описание в нижнем регистре
            LOOKUP_MAP.put(String.valueOf(status.code), status);
            LOOKUP_MAP.put(status.description.toLowerCase(), status);
        }
    }

    HttpStatus(int code, String description) {
        this.code = code;
        this.description = description;
    }

    public static HttpStatus fromString(String key) {
        if (key == null) return null;
        return LOOKUP_MAP.get(key.trim().toLowerCase());
    }
}

Преимущества: поиск за O(1), легко добавлять новые сопоставления.
Недостатки: требует больше памяти, нужно обновлять map при изменении enum.

Этот метод идеален для enum с фиксированным набором констант и частыми запросами, например, в парсерах или конфигурационных файлах.