Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I define duplicate enumeration constants in Java?

Tags:

java

enums

I want to define an enum type with two constants whose "value" is the same. I call these two constants as duplicates. Consider the following example: I want to define a list of browser types, and I want to have both a literal "IE" and "InternetExplorer", as below:

enum Browser {
    CHROME("chrome"),
    FIREFOX("firefox"),
    IE("ie"),
    INTERNETEXPLORER("ie");

    String type;
    Browser(String type) {
        this.type = type;
    }
}

However, with this, the following code will fail,

Browser a = Browser.IE;
Browser b = Browser.INTERNETEXPLORER;
Assert.assertTrue(a==b);

The only workaround I can think of is that to add a value() method of the Browser type that returns the internal value of the browser instance. And the equality test code would be

Assert.assertTrue(a.value()==b.value())

This is not nice. So does anyone have a better idea?

Why does Java not allow to override methods like equals() of Enum<T> class?

EDIT:

OK, thanks for the answers and comments. I agree that my original thought was against the purpose of enum. I think the following changes can meet my need.

public enum Browser {
   CHROME,
   FIREFOX,
   IE;

   public static Browser valueOfType(String type) {
       if (b == null) {
            throw new IllegalArgumentException("No browser of type " + type);
       switch (type.toLowerCase()) {   
          case "chrome":
               return Browser.CHROME;
          case "firefox":
               return Browser.FIREFOX;
          case "ie":
          case "internetexplorer":
          case "msie":
               return Browser.IE;
          default:
               throw new IllegalArgumentException("No browser of type " + type);
       }
   }
}
like image 712
Ming Xue Avatar asked Sep 20 '12 11:09

Ming Xue


People also ask

Can enum have duplicate values in Java?

CA1069: Enums should not have duplicate values.

How do you declare an enum constant in Java?

A Java enum is a data type that stores a list of constants. You can create an enum object using the enum keyword. Enum constants appear as a comma-separated list within a pair of curly brackets. An enum, which is short for enumeration, is a data type that has a fixed set of possible values.

Can 2 enums have the same value?

Two enum names can have same value. For example, in the following C program both 'Failed' and 'Freezed' have same value 0.

Can we have enum containing enum with same constant?

The values assigned to the enum names must be integral constant, i.e., it should not be of other types such string, float, etc. All the enum names must be unique in their scope, i.e., if we define two enum having same scope, then these two enums should have different enum names otherwise compiler will throw an error.


2 Answers

Hierarchical enumeration trick is probably what you want in this case. Although it doesn't solve the comparison problem, it provides a very nice alternative to you problem.

http://java.dzone.com/articles/enum-tricks-hierarchical-data

I quote the codes from the site above directly with slight simplification:

public enum OsType {
    OS(null),
        Windows(OS),
            WindowsNT(Windows),
                WindowsNTWorkstation(WindowsNT),
                WindowsNTServer(WindowsNT),
            WindowsXp(Windows),
            WindowsVista(Windows),
            Windows7(Windows),
        Unix(OS),
            Linux(Unix),
    ;
    private OsType parent = null;

    private OsType(OsType parent) {
        this.parent = parent;
    }
}
like image 94
gigadot Avatar answered Sep 22 '22 23:09

gigadot


Each enum mutually extends class Enum that defines equals() as final. This is done because enum is not a regular class. JVM guarantees that each enum element is unique, i.e. exists only one instance of each element within one JVM.

This is required for example for using enums in switch statement etc.

What you are trying to do is to go against this concept: you want to have 2 equal members of the same enum.

However I can offer you other solution: define only one IE member. Define String[] member into the enum and method that can find appropriate member by any alias:

public enum Browser {


    CHROME("Chrome"),
    FIREFOX("FireFox"),
    IE("IE", "MSIE", "Microsoft Internet Exporer"),
    ;

    private String[] aliases;

    private static Map<String, Browser> browsers = new HashMap<>();
    static {
        for (Browser b : Browser.values()) {
            for (String alias : b.aliases) {
                browsers.put(alias, b);
            }
        }
    }

    private Browser(String ... aliases) {
        this.aliases = aliases;
    }

    public static Browser valueOfByAlias(String alias) {
        Browser b = browsers.get(alias);
        if (b == null) {
            throw new IllegalArgumentException(
                    "No enum alias " + Browser.class.getCanonicalName() + "." + alias);
        }
        return b;
    }
}
like image 39
AlexR Avatar answered Sep 21 '22 23:09

AlexR