1. 概述

在这篇短文中,我们将深入探讨“IllegalArgumentException: No enum const class" 异常。

首先,我们将理解这种异常背后的原因。接着,通过一个实际例子来重现它,最后学习如何修复它。

2. 原因

在深入了解之前,我们先理解这个异常及其堆栈跟踪的含义。

通常情况下,当我们将非法或不合适的值传递给方法时,会抛出 IllegalArgumentException

No enum const class" 提示我们在指定的枚举类型中没有找到具有给定名称的常量。

所以,这种异常最常见的原因是通常使用无效的枚举常量作为方法参数。

3. 重现异常

现在我们知道异常的含义了,让我们通过一个实际例子来重现它。

例如,考虑 Priority 枚举:

public enum Priority {

    HIGH("High"), MEDIUM("Medium"), LOW("Low");

    private String name;

    Priority(String name) {
        this.name = name;
    }

    public String getPriorityName() {
        return name;
    }

}

如图所示,我们的枚举有一个私有字段 name,表示每个 Priority 常量的名称。

接下来,我们创建一个静态方法来通过名称获取一个 Priority 常量:

public class PriorityUtils {

    public static Priority getByName(String name) {
        return Priority.valueOf(name);
    }

    public static void main(String[] args) {
        System.out.println(getByName("Low"));
    }

}

现在如果我们执行 PriorityUtils 类,就会得到一个异常:

Exception in thread "main" java.lang.IllegalArgumentException: No enum constant com.baeldung.exception.noenumconst.Priority.Low
    at java.lang.Enum.valueOf(Enum.java:238)
    at com.baeldung.exception.noenumconst.Priority.valueOf(Priority.java:1)
....

查看堆栈跟踪,getByName(String name) 方法由于内置方法 Enum.valueOf(Class<T>, String) 未能找到名称为“Low" 的 Priority 常量而失败。

Enum.valueOf() 方法只接受必须与枚举中声明常量标识符完全匹配的字符串。换句话说,它只接受 HIGHMEDIUMLOW 作为参数。由于它不知道 name 属性,当我们传入值“Low” 时,它会抛出 IllegalArgumentException

现在,让我们用测试案例来验证这一点:

@Test
void givenCustomName_whenUsingGetByName_thenThrowIllegalArgumentException() {
    assertThrows(IllegalArgumentException.class, () -> PriorityUtils.getByName("Low"));
}

4. 解决方案

最简单的解决方案是在将自定义的 name 传递给 Enum.valueOf() 方法之前,先将其转换为大写。这样可以确保传递的字符串与常量名称完全匹配,这些名称都是大写的。

现在,让我们看看它是如何工作的:

public static Priority getByUpperCaseName(String name) {
    if (name == null || name.isEmpty()) {
        return null;
    }

    return Priority.valueOf(name.toUpperCase());
}

为了防止任何 NullPointerException 或意外行为,我们添加了一个检查,确保给定的名称不为 null 并且不为空。

最后,我们添加一些测试用例以确认一切都按预期工作:

@Test
void givenCustomName_whenUsingGetByUpperCaseName_thenReturnEnumConstant() {
    assertEquals(Priority.HIGH, PriorityUtils.getByUpperCaseName("High"));
}

正如我们所见,我们成功地使用自定义名称 High 获取到了 Priority.HIGH

现在,让我们看看当我们传递 null 或空值时会发生什么:

@Test
void givenEmptyName_whenUsingGetByUpperCaseName_thenReturnNull() {
    assertNull(PriorityUtils.getByUpperCaseName(""));
}

@Test
void givenNull_whenUsingGetByUpperCaseName_thenReturnNull() {
    assertNull(PriorityUtils.getByUpperCaseName(null));
}

如上所述,方法确实返回了 null

5. 总结

在这篇简短教程中,我们详细讨论了Java为何抛出“IllegalArgumentException: No enum const class" 异常的原因。

途中,我们学会了如何产生这个异常,并通过实际例子学习了如何修复它。

如往常一样,所有示例的完整源代码可在GitHub 上找到。