Thursday, November 02, 2006

Java enum misuse

The Java enum is a nice feature, but like anything it is open to abuse. Witness:

enum OverTheTop {
    A, B;

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(final String value) {
        this.value = value;
    }
}

Even though the instances of OverTheTop are fixed and immutable, enums are after all simply class instances and can be use anyway a class can be used. This is the same problem with unmodifiable collections having modifiable members.

You could view enums as a generalization of singletons, having a fixed number of members not limited to just one. (Class loading is thread safe — does this mean one can use a single-member enum to implement a thread-safe singleton?)

As abusive as enums with setters seems, worse still remains:

enum TrulyUnpredictable {
    A, B;

    private Runnable runnable;

    public void setRunnable(final Runnable runnable) {
        this.runnable = runnable;
    }

    public void run() {
        new Thread(runnable).start();
    }
}

As unmaintainable as this seems (what does TrulyUnpredictable.A.run() do?), there are legitimate uses for complex enums.

Say you have a limited set of algorithm implementations and would like to switch on them:

enum Algorithm {
    FAST(ImplementationFactory.getInstance("FAST")),
    ACCURATE(ImplementationFactory.getInstance("ACCURATE")),
    EFFICIENT(ImplementationFactory.getInstance("EFFICIENT"));

    private final Implementation implementation;

    Algorithm(final Implementation implementation) {
        this.implementation = implementation;
    }

    public double calculate() {
        return implementation.calculate();
    }
}

And for the fan of difficult syntax:

enum Algorithm {
    FAST() {
        public double calculate() {
            new FastImplementation().calculate();
        }
    },
    ACCURATE() {
        public double calculate() {
            new AccurateImplementation().calculate();
        }
    },
    EFFICIENT() {
        public double calculate() {
            new EfficientImplementation().calculate();
        }
    };

    public abstract double calculate();
}

There are very many variations on these themes, but it is not too difficult to reach the point where no one can read your code except you.

5 comments:

Ricky Clarkson said...

"there are legitimate uses for complex enums."

I'm not sure what case would suggest mutable enum members. Can you expand on that a little?

"And for the fan of difficult syntax"

Yes, the syntax of anonymous enum members seems odd at first, but I prefer to implement them that way if the alternative would be a switch statement.

Anonymous said...

Thank you so much! I was hoping to find some tickets to see a cheap madonna.

The only example I can come with for mutable enums is if some value of the enum needs to be read from a database or configuration file. The value is still immutable logically, but would need to be mutable from the perspective of the class loader.

Anonymous said...

HEY KEWL PAGE. I WAS GOOGLING 4 CHEAP C-WORLD TICKETS AND UR SITE IS DA BEST!!!!!

I think enums are really a needed feature, but they just seem too flexible to me. The compiler should force any class-members to be final. That would cut down on a lot of the insanity.

On another note, you can implement interfaces but not extend other enums? I agree with you on that alternative (difficult) syntax being a bit unnecessary.

Anonymous said...

This is reminding me of C++ now... please, Java developers, do not turn this into the complicated nightmare of C++. Just because we are capable of taking things to the complicated extreme, it doesn't help us to produce programs that benefit people. Frustrating.

Anonymous said...

it is cool.