java.lang.EnumConstantNotPresentException 什么时候被抛出?

When does java.lang.EnumConstantNotPresentException gets thrown?

根据 java API 当应用程序尝试按名称访问枚举常量并且枚举类型不包含具有指定名称的常量时,将抛出 EnumConstantNotPresentException。

因此我决定想出一个会抛出java.lang.EnumConstantNotPresentException的场景,所以我写了下面三个class。

MyEnum class:

package my.enumtest;

enum MyEnum {
    A, B, C;
}

MyEnumTest1 class:

package my.enumtest;

    import my.enumtest.MyEnum;

    class MyEnumTest1 {

        public static void main(String [] args) {
            System.out.println(MyEnum.A);        
        }        
    }

MyEnumTest2 class:

package my.enumtest;

import my.enumtest.MyEnum;

class MyEnumTest2 {

    public static void main(String [] args) {
        System.out.println(MyEnum.valueOf("A"));        
    }
}

我编译了所有三个,然后我将 MyEnum class 更改为删除常量 'A' 并重新编译它:

package my.enumtest;

enum MyEnum {
    B, C;
}

在使用新的 MyEnum class 执行 MyEnumTest1 时,出现以下异常:

Exception in thread "main" java.lang.NoSuchFieldError: A at my.enumtest.MyEnumTest1.main(MyEnumTest1.java:8)

在使用新的 MyEnum class 执行 MyEnumTest2 时,出现以下异常:

Exception in thread "main" java.lang.IllegalArgumentException: No enum constant my.enumtest.MyEnum.A at java.lang.Enum.valueOf(Unknown Source) at my.enumtest.MyEnum.valueOf(MyEnum.java:3) at my.enumtest.MyEnumTest2.main(MyEnumTest2.java:8)

正如您在 none 个案例中看到的那样,我得到了 EnumConstantNotPresentException,所以有人可以向我提供 EnumConstantNotPresentException class 的用法吗?

P.S. 我知道这个异常可以由 API 抛出,用于反射性地阅读注释,但我正在寻找更明显(更简单) 场景。

如果您想知道特定异常何时被抛出,您应该做的第一件事就是阅读 the documentation,正如 JB Nizet 提到的那样。它说:

Thrown when an application tries to access an enum constant by name and the enum type contains no constant with the specified name. This exception can be thrown by the API used to read annotations reflectively.

link 跟在 AnnotationElement 之后,文档说:

Similarly, attempting to read an enum-valued member will result in a EnumConstantNotPresentException if the enum constant in the annotation is no longer present in the enum type.

这足以制作一个示例。 创建以下 classes:

// TestEnum.java
public enum TestEnum {
    A, B, C;
}

// TestAnnotation.java
import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    TestEnum value();
}

// TestClass.java
@TestAnnotation(TestEnum.C)
public class TestClass {

}

// ReadAnnotation.java
public class ReadAnnotation {
    public static void main(String[] args) {
        System.out.println(TestClass.class.getAnnotation(TestAnnotation.class).value());
    }
}

编译所有内容并 运行 ReadAnnotation。你会得到 C.

现在从 TestEnum 中删除 C 并仅重新编译 TestEnum class 保留其他 class 原样。如果您现在启动 ReadAnnotation,您将获得:

Exception in thread "main" java.lang.EnumConstantNotPresentException: TestEnum.C
    at sun.reflect.annotation.EnumConstantNotPresentExceptionProxy.generateException(Unknown Source)
    at sun.reflect.annotation.AnnotationInvocationHandler.invoke(Unknown Source)
    at com.sun.proxy.$Proxy1.value(Unknown Source)
    at ReadAnnotation.main(ReadAnnotation.java:4)

如果您想知道它是否可以被其他任何东西抛出,您可以扫描 JDK 来源以查找此异常名称。我没有发现任何其他提及此异常的情况,因此似乎反射是唯一可能的情况。

java 中的枚举通常也称为 合成糖 这是什么意思?

枚举常量在编译时被转换为 public static final MyEnum 字段,其中包含枚举常量的名称和 class 的构造函数的值。 这意味着通过访问 MyEnum.MY_CONSTANT,您可以访问 字段 :

public static final MyEnum MY_CONSTANT = new MyEnum();

由于反射 API 现在还提供了通过 getEnumConstants()isEnumConstant() 检查枚举常量的方法(请参阅指南中的枚举枚举),java 有一种方法判断哪个字段是枚举常量,哪个字段不是。所以这些字段并不像您在第一段之后想的那么简单。

NoSuchFieldException 被抛出是因为......相应的枚举没有创建这样的字段。

IllegalArgumentException 由反射 API 抛出,因为它是为 API 设计的异常,例如 Enum#valueOf()。该方法使用反射按名称(字符串)查找给定的枚举常量。