How can I define duplicate enumeration constants in Java? - java

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

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

One simple way to do this is to put instance variables inside your enum class.
enum Browser {
CHROME,
FIREFOX,
INTERNETEXPLORER;
public static final Browser IE=INTERNETEXPLORER;
}
Then, IE should just act as an alias to INTERNETEXPLORER, and you can use them interchangeably.
EDIT: Thanks to big_m for suggesting to make IE final!
EDIT2: This trick should work in most code, but there's an exception if you are using switch/case. Here's an example:
Browser b;
switch(b){
case Browser.CHROME:
//code for chrome
break;
case Browser.IE: // <---- SYNTAX ERROR, use Browser.INTERNETEXPLORER in this case
//code for internet explorer
break;
}

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

You can't override the equals() method for an enum, but even if you could the == operator does not execute the equals() method: There is no way to make a == b be true for your example.
The closest I can think of is a utility (static) method:
enum Browser {
CHROME("chrome"),
FIREFOX("firefox"),
IE("ie"),
INTERNETEXPLORER("ie");
private final String type;
Browser(String type) {
this.type = type;
}
public String getType() {
return type;
}
public static boolean equals(Browser b1, Browser b2) {
return b1.type.equals(b2.type);
}
}
Also note that I would make type private final. As it is, you can do this:
IE.type = "netscape"; // would be allowed

What you should really do is normalize the conversion of input to enum, i.e. if your input (from user/data store) is IE/INTERNETEXPLORER, it should be resolved to Browser.IE. That would remove a lot of redundant checks in the code to see if the enum is IE or INTERNETEXPLORER.

As Written In EnumClass
but extending this class does not make a class an enumeration type, since the compiler needs to generate special information for it.
In order to support equality based on reference equals method is final.
You can use EnumSet to create EnumSet of Related enums and then you can use contains method.
public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE,
Browser.INTERNETEXPLORER);
So your code will look something like below.
public enum Browser {
CHROME("chrome"), FIREFOX("firefox"), IE("ie"), INTERNETEXPLORER("ie");
String type;
Browser(String type) {
this.type = type;
}
public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE,
Browser.INTERNETEXPLORER);
public static void main(String[] args) {
System.out.println(MSE.contains(Browser.IE));//true
System.out.println(MSE.contains(Browser.INTERNETEXPLORER));//true
}
}

I would remove the string value and the duplicate IE instance, its of no use ...
enum Browser {
CHROME,
FIREFOX,
IE
If you must have lower case representation just convert from enum name when you need it.

Related

How to inherit functionalities to reduce repeating codes in enums?

In a Java application I'm working on, I have a number of enums which ended up having a static fromString method in them for converting a string to its actual enum value.
So, I thought I could have a "base" class from which all my enums can extend without have to repeat that code all the time. Since enums cannot extend classes, I've planned to do is that I might be able to do that through an interface instead.
What I've is the following:
public interface IBaseEnum {
String enumVal = null;
public static <T extends Enum<T> & IBaseEnum> Enum<T> fromString(String strVal) {
if (strVal == null) return null;
// T.values() has error because T is not recognised to have the method values()
for (T myEnum : T.values()) {
if (myEnum.enumVal.equals(strVal.toUpperCase())) {
return myEnum;
}
}
return null;
}
}
And then, to inherit that static method, I will implement IBaseEnum in my actual Enum:
public enum Colour implements IBaseEnum {
Red("red");
//...
}
However, I'm having issues with the types in IBaseEnum. The line T.values() is having error because the generic type T cannot be referenced back to the enum itself and so it is complaining that the method values() is not found.
Is this the right way to inherit functionalities in enum? Otherwise, how can I inherit methods in enums so that I don't have to copy/paste and repeat a same set of methods in every single enums?
There are a few reasons why your code would not work, of which I should mention:
String enumVal = null;: IBaseEnum being an interface, numVal gets the implicit public, static, and final modifiers. However, you intend enumVal to be an instance property.
T.values(): of course this doesn't compile. But even if it could (or you had the class instance), you still wouldn't be able to make this dynamic. Static methods are picked at compile time. The only way (that I know) to make it work dynamically would be to use reflection, of course passing in the class object of the enum.
Because you want to be able to call Color.fromString(...), you have no choice but to declare this as a static method in each enum class. With that said, I think the most you can reuse from your logic is the lookup code (again, that's unless you use reflection).
To reuse the lookup logic, you can change the contract of IBaseEnum to make it declare a method that that returns the enumVal value. Beside that, the values() method can be invoked by the enum classes themselves. Here's what it can look like:
interface IBaseEnum {
String enumVal();
public static <T extends Enum<T> & IBaseEnum> T
fromString(String strVal, T[] values) {
if (strVal == null)
return null;
for (T myEnum : values) {
if (myEnum.enumVal().equalsIgnoreCase(strVal)) {
return myEnum;
}
}
return null;
}
}
And that will lead to an enum class like the following:
enum Colour implements IBaseEnum {
VAL1("string")
;
private final String val;
Colour(String v) {
this.val = v;
}
#Override
public String enumVal() {
return this.val;
}
public static Colour fromString(String s) {
return IBaseEnum.fromString(s, values());
}
}
Remember: if enumVal() is intended to return just the enum literal, then you can get rid of all this complexity by just using the valueOf method available in all enums. Only do this if the comparison of your values needs custom logic.

Java nested enum understanding

I want to ask about nested enums. I am working with old code and i found very strange construction that i not really good understand.
I have this enum :
public enum DbEngines {
ORACLE("oracle", "set define on", "set define off")
, POSTGRESQL("postgresql", "--TODO set define on", "--TODO set define off");
private final String dbEngine;
private String setOn;
private String setOff;
DbEngines(String dbEngine, String setOn, String setOff) {
this.dbEngine = dbEngine;
this.setOn = setOn;
this.setOff = setOff;
}
public String getSetOn() {
return setOn;
}
public String getSetOff() {
return setOff;
}
public String toString() {
return this.dbEngine;
}
}
I added private String to this enum, that are engine specific, so it is good place for me here. The problem is, that in some places in method declaration i see something like that
public someMethod(Enum<DbEngines> engine, ...)
And it worked perfectly without methods, but now, after changing, I couldn't call public getters of this enum. But if i change to :
public someMethod(DbEngines engine, ...)
it works without any problems with all public getters. Maybe someone could explain that?
Enum in Java is the base class for all enumeration types. One can think of it as similar to Object class.
Just like one can hold reference of object of any class using the reference of type Object, one can refer to an enumeration type using the reference of type Enum.
Object o = new Integer(10);
Enum e = DBEngine.ORACLE;
One cannot invoke a method present in inherited class but absent in superclass using the reference of superclass.
Similar explanation over here.

Can Eclipse (or any IDE) introduce type parameters to an existing type

This is the exact opposite of how can I remove generic type from class using refactoring.
I want to introduce a type parameter to an interface. It is used quite extensively, so not very practical to do by hand. It is also widely used in import statements and JavaDoc, so a simple global string replace will not work very well either.
Edit:
I did try the "use parent type when possible" refactoring, but it understandably did not work very well at introducing type parameters.
In IntelliJ, you can use the "Change Signature" refactoring. Given this code:
public static void main(String[] args) {
MyContainer container = new MyContainer("hello!");
String val = container.get();
System.out.println(val);
}
class MyContainer {
final Object value;
MyContainer(Object value) {
this.value = value;
}
Object get() {
return value;
}
}
I right-clicked on MyContainer, then chose Refactor->Change Signature... From here, you can introduce a type parameter T. You need to give a default concrete type for T. Most of the time, to preserve existing code, this would be Object; but it depends on the class you're changing. For example, if MyContainer above used Number instead of Object, the equivalent of the new erasure type would be Number. But you would also need to declare T extends Number in that case.
When I finish this, I get the following:
public static void main(String[] args) {
MyContainer<Object> container = new MyContainer<Object>("hello!");
String val = (String) container.get();
System.out.println(val);
}
class MyContainer<T> {
final Object value;
MyContainer(Object value) {
this.value = value;
}
Object get() {
return value;
}
}
Now you can start to use T in MyContainer, and by looking at the files that IntelliJ changed, you can start to see where you need to look to start filling in the correct type arguments (since all auto-generated type parameters will be Object).

Enum value internationalization at Wicket

I have an enum FooBar at class Clazz with falues FOO and BAR like this:
class Clazz {
enum FooBar{
FOO,
BAR
}
}
I now would like to use wicket getString() method to localize the values FOO and BAR. The best I can do is to define at i18n file
Clazz.FooBar.FOO=foo
Clazz.FooBar.BAR=bar
and I get values with this code
fooBar = FooBar.FOO;
getString("Clazz.FooBar." + fooBar.name());
I have heard that this could be achieved without Clazz.FooBar addition to the i18n query string, but the method to be called would be different. How to do this?
You can put this method in your base page/panel:
public String getString(Enum<?> value) {
Class<?> enclosingClass = value.getClass().getEnclosingClass();
String key = (enclosingClass == null ? "" : enclosingClass.getSimpleName() + ".")
+ value.getClass().getSimpleName() + "." + value.name();
return getString(key);
}
Then you can simply call it with
getString(Clazz.FooBar.FOO);
and it will return what you defined in the property file.
I will not advice you to directly store enum constant names in properties file the reason is simple two different enums can hold same name.
Below is the code I have come up with
class Clazz {
enum FooBar {
//StrId are keys from property file e.g. below
FOO("com.abc.classz.foobar.FOO"), BAR("com.abc.classz.foobar.BAR");
private final String strId;
private FooBar(String id) {
this.strId = id;
}
// toString can also be used here I am just keen on having seperate
// method
public String getName() {
//Load Value for strId from properties file
return null;
}
}
}
This will keep your enum and your i18n purpose separate and clear.
See below sample Enum class. You may want to customize it more depending on your needs.
public enum FooBar {
foo("foobar.foo"),
bar("foobar.bar");
private String key;
ErrorCodeEnum(final String key) {
this.key = key;
}
public String toString() {
return key;
}
}
then you can make the toString method to return key directly so you can use
getString(ErrorCodeEnum.ERROR1);
or you can override the toString method directly like below
public enum FooBar {
foo, bar;
public String toString(){
return getClass().getName()+"."+name();
}
}
You could simply define
FOO=foo
BAR=bar
in your properties and access it by
getString(fooBar.name());
or am I missing some point?
I was looking for something called EnumChoiceRenderer. The main idea is to give a EnumChoiceRenderer for e.g. DropDownChoise element and you're able to give parameters of the kind I was proposing in my question. Ok, in this solution you're able to give only
FooBar.BAR=bar
FooBar.FOO=foo
in your resource file but this is the closest I could find when I investigated this more with my spare time.
PS. Click the EnumChoiseRenderer in the beginning of this answer to see the article of this solution.

Can Java methods return type Enum?

I could be wrong but I'm guessing from Why can't enums be declared locally in a method?
that, since an enum in Java cannot be declared locally, that therefore it is problematic for a method to return type Enum? I can declare that a method should return an Enum (see below) but how would one then go about implementing such a method to return anything other than null, or a reference to an Enum declared outside the method? My first inclination would be to investigate using Generics for this but I'd like to avoid any deadends if the SO community can help me avoid them.
private Enum resources() {
return null;
}
I think you're correct, it's only going to be able to either return null or an Enum declared somewhere else. But you don't necessarily have to specify that "something else" at compile time.
class EnumEnumerator<T extends Enum<T>> implements Iterable<T> {
private final Class<T> enumClass;
public EnumEnumerator(Class<T> enumClass) {
this.enumClass = enumClass;
}
public Iterator<T> iterator() {
T[] values = enumClass.getEnumConstants();
return Arrays.asList(values).iterator();
}
}
Later, you invoke it by specializing the generic constructor and passing in the enum class you're interested in:
class EnumEnumeratorDemo {
enum Foo {
BAR, BAZ, QUX;
#Override public String toString() {
return name().toLowerCase();
}
}
public static void main(String[] args) {
for (Foo f : new EnumEnumerator<Foo>(Foo.class)) {
System.out.println(f);
}
}
}
(Obviously this is a contrived example and in real life you should just call Foo.values(), but you get the idea.)
The entire point of the way Java does Enums is that they are typesafe--so you wouldn't return an Enum (that would be double-plus ungood) instead you return the actual type you define (like "Suit") which acts just like a class. Suit has 4 "Enumerated" instances.
If you were expecting a "Suit", what good would it be to return a "Rank" of 7? It would break everything!
Also if you passed an "Enum" or some generic value, you couldn't call methods on it. The coolest thing about TypeSafe Enums is that you can just get a "Suit" and call "Suit.getColor()" and fully expect to get the color of that suit. You could also have a ranksHigherThan(Suit s) which might fulfill:
assertTrue(SPADES.ranksHigherThan(HEARTS));
Or, more importantly:
suit1.ranksHigherThan(suit2);
(assuming they were both passed in and you don't know what they are)
Type safety is really amazing (even though it feels a little uncomfortable at first), embrace it.
All enums implement the interface Enum, so you can certainly write a method that returns an enum this way. But this method will return a single enum value. There is no way to return a generic value which encompasses the whole enum (apart from returning the class and doing reflection). You can however return all the enum values which is more or less what you want I think.
enum Resources { ONE, TWO, THREE }
private Enum<?>[] resources() {
return Resources.values();
}
One benefit of this approach is you can return more or less values for example:
enum Resources { ONE, TWO, THREE }
enum MoreResources { UN, DEUX, TROIS }
private Enum<?>[] resources() {
List<Enum<?>> resources = new ArrayList<Enum<?>>();
resources.addAll(Arrays.asList(Resources.values());
resources.addAll(Arrays.asList(MoreResources.values());
return resources.toList(new Enum<?>[] {});
}
An even better approach that is more typesafe is to have the enums of interest
implement a common interface e.g.
public interface Resources {}
enum SomeResources implements Resources { ONE, TWO, THREE }
enum MoreResources implements Resources { UN, DEUX, TROIS }
private Resources[] resources() {
List<Resources> resources = new ArrayList<Resources>();
resources.addAll(Arrays.asList(Resources.values());
resources.addAll(Arrays.asList(MoreResources.values());
return resources.toList(new Resources[] {});
}
You can add additional methods to the interface to provide more functionality.
What are you trying to accomplish? This is a way to return an Enum:
public class Test
{
public static void main(String args[])
{
System.out.println(doit());
}
public enum Foo {
BAR,
BAZ;
}
public static Enum doit() {
return Enum.valueOf(Foo.class,"BAR");
}
}
But, I'm guessing this is not what you are going for?
Yes, it definitely is possible.
private Enum getRetentionPolicy() {
return java.lang.annotation.RetentionPolicy.SOURCE;
}
If your question is about declaring Enums, you may declare them:
in their own java file, similar to a top-level class;
within a java file belonging to another class, similar to a static inner class;
Not totally sure what your goal is, but if you wanted to return a generified method (i.e. one that would be overridden) you might have something like the following:
public class MyEnumClass<T extends Enum<T>> {
public T resources() {
//do stuff here
}
}
Not entirely sure what you would gain there, although it can be beneficial if you are talking about different sets of Enums and their elements.
If you are talking about the Enum class (i.e. the percursor to Iterator) as far as I know it has not been generified, so I am not sure generics would help much here.
You can refer to a value of an enum by its name, e.g. Suit.SPADES.
You can iterate over all values by using the values() method and pick one of the values.

Categories