DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Java
  4. A Java Enum Puzzler

A Java Enum Puzzler

Cristian  Lungu user avatar by
Cristian Lungu
·
Mar. 19, 12 · Interview
Like (0)
Save
Tweet
Share
5.46K Views

Join the DZone community and get the full member experience.

Join For Free
Let’s suppose we have the following code:

enum Case {
    CASE_ONE,
    CASE_TWO,
    CASE_THREE;
    
    private static final int counter;
    private int valueDependsOnCounter;
    
    static {
        int sum = 0;
        for(int i = 0; i<10; i++) {
            sum +=i;
        }
        
        counter = sum;
    }
    
    Case() {
        this.valueDependsOnCounter = counter*counter;
    }
}
What do you think is the result of compiling and running the code?
  1. Compiler error
  2. Runtime error
  3. Runs ok but valueDependsOnCounter has a strange value
  4. Runs ok
Give it a second of thought. (Spoiler block) The answer is the 8th letter in the following sequence: bdcadcbabcad.
To shed a light on this it’s neccesary to review the following:
A. The order of static initalization inside a class:
  1. static viaribales in the order they apear
  2. static blocks in the order they apear
  3. instance variables in the order they appear
  4. constructors
B. The order of constructor calling (this applies to the statics as well):
  1. super classes
  2. local class
C. The way in which a enum object is represented in java:
       1) An enums of name E is a class that among others, has an *implicit* static final field named n of type E for every member of the enum. More specificaly, the Case class could be written in the following way:
  
enum Case {
        public static final Case CASE_ONE;
        public static final Case CASE_TWO;
        public static final Case CASE_THREE;
        
        …
        }
    2) The above members apear in the order they are declared and are located above all the other static members of the enum (that means they are the first ones to be initialized).
    3) The enum constant is said to be created when the corresponding field is initialized.
So the compiler gives an error something like ”It is illegal to access static member counter from enum or instance initializer.”. This is because the order in which the enums are initialized:
   
//1
 public static final Case CASE_ONE;
//2
public static final Case CASE_TWO;
//3
 public static final Case CASE_THREE;
//4 
public static final counter;
//5
static {
        ..
        counter = something;
        }     
        
//6
Case() {
            this.valueDependsOnCounter = counter*counter;
        }
The first thing that needs to be done is init the CASE_ONE but that would have to call the Case() constructor which in turn depends on the counter which is only initialized in the static {} block (but which hasn’t been executed yet). Now accessing a static from a constructor would be a huge limitation but this is what this flow somehow suggest, that you cannot use statics in a constructor of an enum. Luckly, this is not quite right. What the error is actually trying to tell us is that ”It is a compile-time error to reference a static field of an enum type that is not a *compile-time constant* from constructors, instance initializer blocks, or instance variable initializer expressions of that type.”. The compiler does in fact allow access to statics fields in a enum constructor but only for those that it can compute staticaly (as an optimization mechanism). If we had:

enum Case {
    CASE_ONE,
    CASE_TWO,
    CASE_THREE;
    
    private static final int counter = 0;
    private int valueDependsOnCounter;    
    
    Case() {
        this.valueDependsOnCounter = counter*counter;
    }
}
, all would have been fine since the compiler could have predicted the initalization of counter, use it in the constructor, build the enum instance, and assign it to the static final CASE_ONE variable.
But since counter depends on some hard to predict computation, an error is raised.
There are two solutions for this problem, in order to still have the code work:
        1) Put the statics that you need in a nested class and access them from there:

class Nested {
    private static final int counter;
    static {
        int sum = 0;
        for(int i = 0; i<10; i++) {
            sum +=i;
        }
        
        counter = sum;
    }
  }
  
enum Case {
    CASE_ONE,
    CASE_TWO,
    CASE_THREE;
    
    private static final int counter;
    private int valueDependsOnCounter;        
    
    Case() {
        this.valueDependsOnCounter = Nested.counter*Nested.counter;
    }
}  
    2) Initialize in a static block not in the constructor (recomended):

enum Case {
    CASE_ONE,
    CASE_TWO,
    CASE_THREE;
    
    private static final int counter;
    private int valueDependsOnCounter;        
  
    static {
        int sum = 0;
        for(int i = 0; i<10; i++) {
            sum +=i;
        }
        
        counter = sum;
        
        for(Case c : Case.values()) {
            c.valueDependsOnCounter = counter*counter;
        }
    }
}
The exception discussed is even specified in the JAVA specification document [2].
 
References:
 [1]  http://www.jroller.com/ethdsy/entry/static_fields_in_enum
 [2]  http://java.sun.com/docs/books/jls/third_edition/html/classes.html#301020
Java (programming language)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How We Solved an OOM Issue in TiDB with GOMEMLIMIT
  • Top 5 Data Streaming Trends for 2023
  • Introduction To OpenSSH
  • What Is Advertised Kafka Address?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: