sactiw
sactiw

Reputation: 22461

When does java.lang.EnumConstantNotPresentException gets thrown?

As per java API EnumConstantNotPresentException gets thrown when an application tries to access an enum constant by name and the enum type contains no constant with the specified name.

Thus I decided to come up with a scenario where java.lang.EnumConstantNotPresentException will be thrown, so I wrote following three classes.

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"));        
    }
}

I compiled all three and then I changed the MyEnum class to drop constant 'A' and recompiled it:

package my.enumtest;

enum MyEnum {
    B, C;
}

On execution of MyEnumTest1 with new MyEnum class, I got following exception:

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

On execution of MyEnumTest2 with new MyEnum class, I got following exception:

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)

As you can see in none of the cases I got EnumConstantNotPresentException, so can someone provide me usage of EnumConstantNotPresentException class?

P.S. I know that this exception can be thrown by the API used to read annotations reflectively but I am looking for more obvious (simpler) scenario.

Upvotes: 5

Views: 6198

Answers (2)

Marco
Marco

Reputation: 330

An enum in java is often also called synthetic sugar. What is meant with that?

Enum constants are converted to public static final MyEnum fields with the name of the enum constant and the value of the constructor of the class at compile-time. That means by accessing MyEnum.MY_CONSTANT, you access the field:

public static final MyEnum MY_CONSTANT = new MyEnum();

Since the reflection API now also provides methods for examining enum constants (See Enamiming Enums in the Guide) via getEnumConstants() and isEnumConstant(), java has a way to tell which field was an enum constant and which field wasn't. So these fields aren't quite as plain as youd'd think after the first paragraph.

The NoSuchFieldException is thrown because... well there is no such field created by the respective enum.

The IllegalArgumentException is thrown by the reflection API as it is an Exception designed for that API and for example Enum#valueOf(). That method uses reflection to find the given enum constant by name (string).

Upvotes: 0

Tagir Valeev
Tagir Valeev

Reputation: 100269

First thing you should do if you want to know when the specific exception is thrown is to read the documentation as JB Nizet mentioned. It says:

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.

The link follows to AnnotationElement which documentation says:

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.

This is enough to craft an example. Create the following 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());
    }
}

Compile everything and run ReadAnnotation. You will got C.

Now remove the C from the TestEnum and recompile only TestEnum class preserving other classes as is. If you launch ReadAnnotation now, you will get:

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)

If you wonder whether it can be thrown by anything else, you may scan the JDK sources for this exception name. I did not found any other mentions of this exception, so seems that reflection is the only possible case.

Upvotes: 3

Related Questions