Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't enums be declared locally in a method?

Tags:

java

enums

Today, I found myself coding something like this ...

public class LocalEnums {      public LocalEnums() {     }      public void foo() {         enum LocalEnum {             A,B,C         };          // ....         // class LocalClass { }      } } 

and I was kind of surprised when the compiler reported an error on the local enum:

The member enum LocalEnum cannot be local

Why can't enums be declared local like classes?

I found this very useful in certain situations. In the case I was working, the rest of the code didn't need to know anything about the enum.

Is there any structural/design conflict that explains why this is not possible or could this be a future feature of Java?

like image 546
bruno conde Avatar asked Mar 31 '09 13:03

bruno conde


People also ask

Can enum be declared inside a method?

We can an enumeration inside a class. But, we cannot define an enum inside a method. If you try to do so it generates a compile time error saying “enum types must not be local”.

Can enum be declared inside a class?

Yes, we can define an enumeration inside a class. You can retrieve the values in an enumeration using the values() method.

Can enum be declared inside interface?

It's perfectly legal to have an enum declared inside an interface . In your situation the interface is just used as a namespace for the enum and nothing more. The interface is used normally wherever you use it.

Where do you declare enums?

The best way to define the enum is to declare it in header file. So, that you can use it anywhere you want by including that header file during compilation.


2 Answers

Enums are static nested classes because they define static member variables (the enum values), and this is disallowed for inner classes: http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.1.3

Update: I was looking through the JLS (java language specification) for more detail on the restrictions of static nested classes, and didn't find it (although it's probably there, hidden under a different topic). From a pure implementation perspective, there's no reason that this couldn't be done. So I suspect that it was a language philosophy issue: it shouldn't be done, therefore won't be supported. But I wasn't there, so that's pure speculation.

As a comment: if your methods are large enough that they require their own enums, then it's a strong sign that you need refactoring.

like image 55
kdgregory Avatar answered Sep 22 '22 13:09

kdgregory


Other Answers are outmoded as of Java 16 (released 2021-03) and Java 17 (released 2021-09).

Local enums in Java 16+

As part of the records feature introduced in Java 16, enums may now be defined locally. Indeed, records, enums, and interfaces can all be local now.

To quote JEP 395:

The ability to declare local record classes, local enum classes, and local interfaces was introduced.

The addition of local record classes is an opportunity to add other kinds of implicitly-static local declarations.

Nested enum classes and nested interfaces are already implicitly static, so for consistency we define local enum classes and local interfaces, which are also implicitly static.

You can now run the following example code to use an enum defined within a method.

private void demoLocalEnum ( ) {     enum Color { PURPLE, SAFETY_ORANGE }     System.out.println( Color.PURPLE ); } 

In this screenshot, we can see how the local enum exists only within its defining method. A sibling method cannot see that enum. Trying to call that enum from another method generates an error.

Screenshot of an error caused by a sibling method trying to call a local enum defined in some other method.

See a demo of such code running in the IntelliJ 2020.2 IDE.

Implicitly static

There is one limitation with a locally defined enum: No access to state in surrounding class.

Example code:

private void demoLocalEnum () {     int x = 42;      enum Color     {         PURPLE,         SAFETY_ORANGE;          public void demo ()         {             System.out.println( "Now is " + Instant.now() );  // This line works.             System.out.println( "x = " + x );  // ERROR — Non-static variable 'x' cannot be referenced from a static context.         }     }      Color.PURPLE.demo(); } 

My IntelliJ IDE reports error:

Non-static variable 'x' cannot be referenced from a static context

As mentioned in the JEP 395 quote above, a local enum is implicitly static. So any methods you may define on your local enum cannot access state on the surrounding outer class.

To quote JEP 395, regarding local records but applying to local enums as well:

Local record classes are a particular case of nested record classes. Like nested record classes, local record classes are implicitly static. This means that their own methods cannot access any variables of the enclosing method; in turn, this avoids capturing an immediately enclosing instance which would silently add state to the record class. The fact that local record classes are implicitly static is in contrast to local classes, which are not implicitly static. In fact, local classes are never static — implicitly or explicitly — and can always access variables in the enclosing method.

like image 44
Basil Bourque Avatar answered Sep 25 '22 13:09

Basil Bourque