This question already has answers here:
What's the advantage of a Java enum versus a class with public static final fields?
(18 answers)
Closed 8 years ago.
I am getting confused regarding Enum.
Where and how to use Enum?
If I will use Enum instead of constant then what could be the benefit?
Could someone please explain to me?
The primary advantage is type safety. With a set of constants, any value of the same intrinsic type could be used, introducing errors. With an enum only the applicable values can be used.
An Enum class is used to specify a range of constants that will be frequently used within an application.
From http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html:
You should use enum types any time you need to represent a fixed set of constants.
Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.
A constant class (assuming this is what you are talking about), is really specified for one solid object that you wouldn't change. Technically, an Enum class is a constant class with more definitions, but an advantage to an Enum class is some pre-defined functions that you would have to define in your own constant class. However, you should also note that this may be overkill for small, singleton examples.
Additionally, Enum classes are type-safe, whereas static fields aren't. Compile time error checking is now possible, versus the run-time potential errors that will occur with a constant class. This furthermore improves readability, because instead of having errors where an index of a list of constants is unavailable. This is all well explained in this post, by the current best answer.
As of Java 8.0 the keyword "constant" does not exist.
If you mean "const":
This keyword is in the known keywords in Java (from the beginning until today - 8.0),
but it has no use and any compiler shouldn't compile if it find's this keyword.
Enumerations:
Use them when you have specific logical values and don't want to handle them in String,
like:
public enum AcceptableColours {
BLACK,
WHITE,
GREY
}
It's much safer during development time to match enum values
AcceptableColours currentColour = object.getColour;
if (currentColour == acceptableColours.BLACK) {
// do something
} else if (currentColour == acceptableColours.WHITE) {
// do something different
}
than to match string values
AcceptableColours currentColor = object.getColour;
if (currentColor.equals("black")) {
// do something
} else if (currentColor.equals("white")) {
// do something different
}
... imagine huge applications with much more variations on enum values (like banking software, insurance software, ...), where it's much easier to misspell some string values,
and voilà, happy debugging...
Related
I have two enums:
public enum UserType {
USER,
EMPLOYER
}
public enum UserDetails {
USER,
EMPLOYER
}
I try to compare this by this:
if(UserType.USER.equals(UserDetails.USER)){
return true;
}
but i can't because, my equals() throw me this:
equals() between objects of inconvertible types 'UserType' and 'UserDetails'
so, how can I compare two values from two diffrent enums?
Different types
The enum in Java is a class, albeit a slightly special kind of class. A class defines a type.
Unless related by inheritance or by interface, different types cannot be compared for equality. A String cannot be equal to a LocalDate which cannot be equal to a DataSource.
Likewise, an object of enum UserType cannot be equal to an object of enum UserDetails. Apples to oranges, not equal by definition. So, your Question is senseless, technically.
The fact that some enum classes happen to share names on some of their constants has no meaning, it is just coincidence that your two enums share the name USER or EMPLOYER. The enum Month bundled with Java defines a constant named APRIL. I might define another enum with an object also named APRIL. But that does not make them equal.
Asking this question suggests that you have a problem with your design. Perhaps you should post another Question on that design issue if it has but already been addressed on Stack Overflow. As commented by Kayaman, your Question seems like an XY Problem.
The other Answers suggesting you:
Compare the strings of the names of the enum constants.
Compare the ordinal position of the constants within the enum definition.
…are misguided. Those approaches violate the purpose of enums in Java, which is to provide a type-safe identity of certain values known at compile-time.
If you are comparing the names of the constants, then you might as well be using mere String objects rather than enums.
If you are comparing ordinal numbers, then you might as well be using mere integer numbers rather than enums.
Both cases are fragile, resulting in runtime failures if you make a change to one enum without matching the other. And in both cases you have lost the usefulness of the enum, transmogrifying the enum into a confusing level of indirection for a string or int.
Try to compare their names
if(UserType.USER.name().equals(UserDetails.USER.name())){
return true;
}
Reading other answers i've decided to give more extended answer. I have to agree thats such solution is not good enough, cause it's not about enums - it's about string comparing. Enums may be changed and everythig will not work properly. Ok.
I think that there could be better solutions - of course:
Use only one type of enum - it's perfect i think(but author has different enums)
Compare names of enums - well it's working but realy not "clever" use of enum
Make some mapping - why not - but its hard linking of two different enums and it is not good enough
enum UserType {
USER,
EMPLOYER;
public boolean isLike(UserDetails details) {
switch (this) {
case USER:
return details == UserDetails.USER;
case EMPLOYER:
return details == UserDetails.EMPLOYER;
}
return false;
}
}
enum UserDetails {
USER,
EMPLOYER;
}
if(UserType.USER.isLike(UserDetails.USER)){
// do something
}
So we see that's there is no better decision than rewrite the code and make only one enum. But everything depends on the issue:
We don't know why there are two enums - perhaps author supporting legacy code
We don't know why author has to compare these different enums
Does proposed decision solve this concrete problem - yes. Is it good - no
It may be very obvious questions, but is it good to use Enum class if you know that the list of values will keep increasing?
Let's say you define an Event Enum first it contains only [Poo, Too] then as we know we always have some new requirement it becomes [Poo, Too, App, Laa] and that keep changing again and again,
So what is the best approach in this case?
tl;dr
If the entire set of possible values is known at compile-time, use enum.
If values can be added or dropped while your system is in use (at runtime), then you cannot use an enum. Use a Set, List, or Map instead.
Known at compile-time
An enum is appropriate when the domain (set of all possible values) is known at compile-time.
If this year your company is offering two products ( Poo & Too ), then make an enum for those two elements.
public enum Product { POO , TOO }
Next year, your company decides to grow their product offerings by adding App & Laa. As part of a planned deployment, add two more objects to your enum.
public enum Product { POO , TOO , APP , LAA }
By the way, notice the naming conventions. The enum has a regular class name (initial cap). The objects being automatically instantiated are constants, and so are named in all-uppercase.
Also, be aware that the enum facility in Java is quite flexible and powerful, much more so than the usual naming-a-number enum scheme seen in most languages. You can have member variables and methods and constructors on a Java enum. For example, you can add a getDisplayName method to provide text more appropriate to a user-interface than the all-caps object name, as seen in DayOfWeek::getDisplayName. You can add quite a bit of functionality, such as ChronoUnit.between.
What you cannot do at runtime with an enum in Java is add or remove objects. Thus the requirement that you know your domain at compile-time. However, when working with a group of enum objects, you can use the highly-optimized EnumSet and EnumMap classes.
Known at runtime
If you cannot determine the domain at compile-time, if users can add or remove elements at runtime, then use a collection such as a List, Set, or Map rather than an enum.
Singleton
Though not originally intended as a purpose of Enum in Java, an enum happens to be the safest (and simplest) way to implement the Singleton design pattern.
This approach to a singleton is explained in the famous book Effective Java by Dr. Joshua Bloch, et al. Using an enum solves multiple obscure technical problems with other approaches to a singleton.
Your question is pretty generic and I'm pretty sure there is no single right answer. But judging based on spring* tags, I suppose you might be asking about enums in DTOs that being sent over your system in serialized form. If that's the case, I would recommend to choose String in DTO, while inside single app it's ok to use enum. Then you would just care about deserialization/conversion in a factory manner, having ability to handle unknown/missing constant gracefully by logging/providing fallback or meaningful error.
It depends on a case-by-case situation and your question doesn't have much context. However, I do recommend using ENUMs for many cases, including if you expect the list of ENUMs to increase.
Some reasons to use them are:
It creates a definite guide of ENUM elements that can be used throughout your code. It eliminates uncertainty over what something is named or what it is. For example ENUM that contains list of animals, or enum of "something".
Its easy to refactor later if you need to change anything.
I'm sure there are many more reasons, I find it like a table of contents sometimes. For many cases, you can completely avoid it and be fine but I think its better to use it in general if you're on the fence.
When you use an enum type, you have the ability to add arguments to each constant, provide a body for each constant, and provide a body for the type. But if you don't do any of that:
enum enumType { C1, C2, C3 };
is it as efficient to use the enum type as it would be just to declare integer constants?
static final int C1 = 1;
static final int C2 = 2;
static final int C3 = 3; // or whatever
Or is there still some overhead due to this feature (the ability to provide bodies), even though the feature isn't being used in this case?
You didn't specify any kind of context within which the performance should be compared. In most cases the fact that enum members are objects is completely irrelevant because only the reference values are being compared; the objects themselves are not even touched.
However, public static final int are compile-time constants, and their values are hardcoded at the place of usage, which clearly imposes no overhead at all.
So it's very little overhead against no overhead at all, but at the expense of problems with compile-time constants, such that changing any of them requires recompiling everything which references it.
Yes, it's very efficient to use enums. You can even compare two instances of an enum using ==, with the added benefit of type safety:
Fruits.APPLES == Fruits.ORANGES
If you look inside the Enum class, you'll see that the equals() method uses == to compare two instances. And all the heavy lifting of creating enum instances is done at class compilation time, so there's no additional overhead there.
Enum constants offer no appreciable performance penalty when compared to using static final int constants to achieve related functionality. Internally, an enum constant is simply represented as a 32-bit integer. In the context of the JVM, however, an enum constant offers type safety, extensibility, and far more flexibility than you can achieve with int constants.
The only downside to using enum constants over int constants is the time to load and initialize the enum class objects, however this is unlikely to be appreciable in any real world scenario. In the example you give in your question, once the application is loaded and running, there would be no performance penalty for using enums over int constants. Note also that because enum constants are necessarily singletons (guaranteed by the JVM), they may be efficiently compared with the '==' operator for both equality and identity just as you would do with most primitive values.
Joshua Bloch provides an excellent discussion of enum types in Effective Java, 2nd Ed. and makes compelling arguments why enum constants should always be used to express any fixed(or even mostly fixed) set of constants that are known at compile time.
It solely depends on the context in which they are being used. As if you have some related constants then you should use enums and if not then you should use constants. As it is illogical and wrong way to club irrelevant constants together.
Both are inline constants, i.e. that each occurrence of both of them are replaced with their corresponding values and so whenever you made changes to them, you should compile all of the files again, which used them in their code. Otherwise you will get incorrect results.
If you have relevant constants then using enums will be a smart choice. As,
They are serialized.
There is API support provided so that u can use them efficiently and without much overhead.
Let's say I have a constants class containing 200+ static fields :
class AnimalConstants {
static final int AARDVARK = 1;
static final int ANTELOPE = 2;
static final int BEAR = 3;
...
...
static final int ZEBRA = 200;
}
Can anyone explain if there are any negative impact on performance and memory from using such classes.
Would it be better or worse if the class is changed to an interface (e.g. SwingConstants) and being implemented by some classes?
Would it be better or worse if I implement the constants as an Enum class?
I don't think the impact is performance or memory.
I think it has to do with things like readability of code, keeping constants close to where they're used, and fundamental understanding of your problem.
I prefer to declare constants closer to where they're used. I believe they're easier to understand that way.
I would be surprised if the real constants that you claim number 200+ are truly related. If they are, they belong together in one place. If not, I'd say that they should be broken into smaller pieces and declared closer to where they're used.
I'll bet there's more context than your contrived example that would change responses if known.
Sure , enums are great. But see my other comments first.
Of course enum implementation is more ponderous than bunch of int constants but using enum:
you don't need to hardcode actual values of Animals (in your case) that can change later
you don't need to hardcode total number of Animals and you can simply iterate through all animals
methods with parameter of this enum will be understood correctly (foo(Animal animal) is better than foo(int animal))
you can add additional functionality to your enum values later, e.g. internal value isMammal
Would it be better or worse if the class is changed to an interface (e.g. SwingConstants) and being implemented by some classes?
--> That would be a Constant Interface Pattern. If we use interfaces for constant and it is implemented by all classes but if you are developing an API, it is something like you are exposing your implementation details. Above wiki link explains this very well.
In both approach(Interface or Class) I would suggest using final class, create constants and do static import for constants wherever necessary.
Would it be better or worse if I implement the constants as an Enum class?
--> With Enums, this would be the best approach.
Changing any value that has already been compiled into another class may require a full build.
Addendum: See Is it possible to disable javac's inlining of static final variables? for a more thorough examination.
Yes it is okay to create a large number of constants. It is hard to discuss negative impact because we don't know any alternatives because we don't have your functional requirements.
But be assured that the compiler is written to work well with code written by humans. Having a bunch of fields is probably going to be okay.
I feel that constants can be very nice as it can be used in switch case since JDK7, you can compare with == and the variable name can be informative.
Can enum be even better? Yes it can. Explore the features of enums and see if anything is appealing to you
For your kind of vars (Animal Types) i suggest you to use an Enumerator instead of a class. With the number of vars using it shouldn't be a problem for performance as you're only using int primitive. The problem would have occurred if any var has been a class, that are more memory demanding to maintain their structure. I hope to have clarified your doubt (Sorry for the poor english, i'm a little rusted)
In Java, an Enum can do the great things that Enums do, but can also have methods (behavior and logic). What advantage does that have over using a class using an enum? Simple examples to illustrate the point would also be welcome.
Here's a simple example:
enum RoundingMode {
UP {
public double round(double d) {
return Math.ceil(d);
}
},
DOWN {
public double round(double d) {
return Math.floor(d);
}
};
public abstract double round(double d);
}
Enum types are also a great way to implement true singletons.
Classic singleton patterns in Java typically involve private constructors and public static factory methods but are still vulnerable to instantiation via reflection or (de-)serialization. An enum type guards against that.
I'm not quite sure where the title of the question fits in with the rest of it. Yes, Java enums have behaviour. They can have state too, although it should really, really be immutable state. (The idea of a mutable enum value is pretty scary IMO.)
An enum in Java is a fixed set of objects, basically. The benefit is that you know that if you have a reference of that type, it's always either null or one of the well-known set.
Personally I really love Java enums and wish C# had them too - they're much more object-oriented than C#'s enums which are basically "named numbers". There are a few "gotchas" in terms of initialization order, but they're generally fab.
Because the enum instances are singletons, you can use them in switch statements or with == to check equality.
Basically, Java enums are classes (I don't believe there is a difference at the bytecode level), with the additional benefit of having a known fixed set of possible instances and being able to use them in switch statements.
You can emulate the "known fixed set of possible instances" with regular classes (the "typesafe enum" pattern described in countless books and articles), but it's quite some work (repeated for every such class) to get it to work really correctly in regard to Serialization, equals() and hashCode(), and perhaps some other things I forgot. Language-level enums spare you that work. And, as mentioned above, only language-level enums can be used in switch statements.
In our project, we're using Enums for a few things, but perhaps most prominently for i18n purposes - each piece of shown text is given an Enum. The Enum class has a String-returning method that inspects the Locale that is being used, and picks the correct translation from a collection of translations on runtime.
This serves as a dual-purpose - you get code completion from your IDE, and also never forget to translate a string.
The usage is very simple, to the point that it's almost rendundant to give an example, but here's how one might use the translation-enum
System.out.println(Translations.GREET_PERSON.trans()+" "+user.getName());
Or, if you want to be fancy, have the Enum accept arguments, which will, with some magic string manipulation, be inserted in a marked position in the translations string
System.out.println(Translations.GREET_PERSON.trans(user.getName());
Take a look at java/joda time classes, where enums do hell of a lot of job.
Here is an example of java.time.Month:
public enum Month implements TemporalAccessor, TemporalAdjuster {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER;
private static final Month[] ENUMS = Month.values();
public static Month of(int month) {
if (month < 1 || month > 12) {
throw new DateTimeException("Invalid value for MonthOfYear: " + month);
}
return ENUMS[month - 1];
}
// About a dozen of other useful methods go here
}