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

5
根据Java API,当应用程序尝试按名称访问枚举常量,而枚举类型不包含指定名称的常量时,将引发EnumConstantNotPresentException异常。

因此,我决定提出一个场景,其中会抛出java.lang.EnumConstantNotPresentException异常,因此我编写了以下三个类。

MyEnum类:

package my.enumtest;

enum MyEnum {
    A, B, C;
}

MyEnumTest1类:

package my.enumtest;

    import my.enumtest.MyEnum;

    class MyEnumTest1 {

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

MyEnumTest2类:

package my.enumtest;

import my.enumtest.MyEnum;

class MyEnumTest2 {

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

我编译了全部三个文件,然后我修改了MyEnum类以删除常量'A'并重新编译它:

package my.enumtest;

enum MyEnum {
    B, C;
}

当我使用新的MyEnum类执行MyEnumTest1时,我得到了以下异常:
“main”线程中的异常java.lang.NoSuchFieldError:A 在my.enumtest.MyEnumTest1.main(MyEnumTest1.java:8)
当我使用新的MyEnum类执行MyEnumTest2时,我得到了以下异常:
“main”线程中的异常java.lang.IllegalArgumentException:没有枚举常量my.enumtest.MyEnum.A 在java.lang.Enum.valueOf(Unknown Source) 在my.enumtest.MyEnum.valueOf(MyEnum.java:3) 在my.enumtest.MyEnumTest2.main(MyEnumTest2.java:8)
正如您所看到的,在这些情况下都没有出现EnumConstantNotPresentException异常,那么有人可以提供EnumConstantNotPresentException类的用法吗?
P.S. 我知道这个异常可以通过用于反射读取注释的API抛出,但我正在寻找更明显(更简单)的场景。

这是指向EnumConstantNotPresentException类的链接... http://docs.oracle.com/javase/7/docs/api/java/lang/EnumConstantNotPresentException.html。我有一种感觉,我漏掉了什么,问题是什么? - Danielson
5
Java文档(http://docs.oracle.com/javase/7/docs/api/java/lang/EnumConstantNotPresentException.html)说明:*此异常可能会被用于反射读取注释的API抛出。*,并包含一个指向描述何时抛出该异常的类的链接。 - JB Nizet
2个回答

3
如果您想知道特定异常何时被抛出,首先要做的是阅读JB Nizet提到的文档。它说:

当应用程序尝试按名称访问枚举常量并且枚举类型不包含指定名称的常量时抛出。此异常可以由用于反射读取注释的API引起。

链接跟随到AnnotationElement,其文档说明如下:

同样,如果注释中的枚举常量在枚举类型中不存在,则尝试读取枚举值成员将导致EnumConstantNotPresentException

这已足以创建示例。创建以下类:
// 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类,并保留其他类不变。如果你现在启动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源代码中是否有这个异常名称的其他提及。我没有找到其他关于这个异常的提及,所以反射似乎是唯一可能的情况。

2
这是一个很好的例子,但我认为如果您解释一下为什么会触发EnumConstantNotPresentException以及为什么sactiw的例子不会触发,那么它将成为更好的答案。 - Lii
@Tagir 感谢您的回复,但是在我的问题中,我已经有一个脚注提到了使用反射读取注释的 API 可以抛出它们,但我正在寻找更明显(更简单)的情况。基本上,它们可以在任何其他情况下被抛出吗? - sactiw
@sactiw,请查看我回复末尾的注释。 - Tagir Valeev
@Tagir 是的,我理解你的观点,我已经尝试过同样的方法,并没有发现任何用法。但是,API并没有说“这个异常只能由用于反射读取注释的API抛出”,对吧? - sactiw
@sactiw,这样的评论会限制JDK开发人员进一步扩展此异常用法。因此目前它仅用于反射,但开发人员可以在未来自由添加更多的用法模式。 - Tagir Valeev
是的,因此我期望能够看到不止一个例子。至少有一个更简单的例子,它不来自 sun.* 包,这些包是特定于 Oracle jdk 的,未来的版本可能会发生更改。 :) - sactiw

0
在Java中,枚举常量通常也被称为“合成糖”。这是什么意思呢?
枚举常量在编译时会被转换为具有枚举常量名称和类构造函数值的公共静态final MyEnum字段。这意味着通过访问MyEnum.MY_CONSTANT,您可以访问该字段
public static final MyEnum MY_CONSTANT = new MyEnum();

由于反射API现在还提供了一些方法来检查枚举常量(请参阅指南中的Enamiming Enums)通过getEnumConstants()isEnumConstant(),Java可以知道哪个字段是枚举常量,哪个不是。所以这些字段并不像你在第一段想的那么简单。 < p > NoSuchFieldException被抛出,因为......好吧,没有由相应枚举创建的这样的字段。< / p > < p > IllegalArgumentException由反射API抛出,因为它是设计用于该API和例如Enum#valueOf()的异常。该方法使用反射按名称(字符串)查找给定的枚举常量。


不确定您是否仔细阅读了问题,因为示例中的第三个类使用了valueOf()方法,正如预期的那样,它会抛出java.lang.IllegalArgumentException: No enum constant而不是EnumConstantNotPresentException。 - sactiw
实际上,我误读了原帖中的实际问题。我的回答只是解释了一些关于枚举的差异,并没有回答你的问题。 - Marco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接