Naming of enums in Java: Singular or Plural? - java

Is there an "official" recommendation of how to name Java enums?
enum Protocol { HTTP, HTTPS, FTP }
or
enum Protocols { HTTP, HTTPS, FTP }
I know in the .Net world the recommendation is to use singular except for enums that represent bit flags. Just curious if there is something similar in Java.
A related question that seems to be .Net specific: Singular or plural for enumerations?

Enums in Java (and probably enums in general) should be singular. The thinking is that you're not selecting multiple Protocols, but rather one Protocol of the possible choices in the list of values.
Note the absence of plurals: http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

In the same way that when you are defining a table name in a database or a class in Java you use singular for enums it's also the best option. Just see how you are going to use it.
Let's write an example:
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
class Appointment {
private Day day;
public void setDay(Day day) {
this.day = day;
}
}
In singular form you see clearly the intention of the day attribute. "day" its the day of the week this appointment is going to be held. Otherwise the signature of the method would have been setDay(Days day) and for sure a lot of people will be wondering if the appointment could happen in more than one day.
If you work in a company the has 48 hour shifts you could try to define something like:
public enum Days {
MONDAY_TUESDAY, WEDNESDAY_THURSDAY, FRIDAY_SATURDAY
}
That way you could set the days you are going to work. But still it will look weird and there is a better option and is to use the singular form:
public enum Shift {
MONDAY_TUESDAY, WEDNESDAY_THURSDAY, FRIDAY_SATURDAY
}
Now you really are showing the meaning of the enum. Usually in any domain you are going to find that using singular for an enum is the best option as each constant in the enum is just one element.
You also mention .NET. A "flags" enum in .NET just means that when you are expecting that enum as a parameter what you really get is a list of elements of that enum (stored as a integer).
// Define an Enum with FlagsAttribute.
[FlagsAttribute]
enum MultiHue : short
{
Black = 0,
Red = 1,
Green = 2,
Blue = 4
};
public void setMultiHue(MultiHue hues);
You could do the same in Java, but the enum still will be singular:
public enum Hue {
BLACK, RED, GREEN, BLUE;
private final Integer hue;
Hue() {
this.hue = 1 << this.ordinal();
}
public Integer toFlag() {
return this.hue;
}
}
public class MultiHue {
private Integer hues = 0;
public void addHue(Hue hue) {
this.hues |= hue.toFlag();
}
public boolean hasHue(Hue hue) {
return (this.hues & hue.toFlag()) != 0;
}
}
An easier and clearer (although it uses a more memory) to do this with Java is just to use a List.

Related

Nested Enums with Constructors & Methods?

I'm a Java student (relatively new) working on a game clone in Java as a side project. In the game, the player controls characters. Each character is part of a faction, and each faction has a set list of skills. The skills of one faction can not be used by any other faction. My idea for how to organize this is with nested enums, where a main Skills enum has multiple inner enums (Faction1, Faction2, etc). The idea is that I would be able to access the data for any specific skill using something along the lines of Skills.Faction1.SKILL_NAME, and to be able to access a full list of a faction's skills using Skills.Faction1.values(). A simplified example of a failed implementation of this is as follows:
public enum Skills {
FACTIONLESS_SKILL("arbitraryArgs"); //More skills than just this one
enum Faction1 {
FACTION1_FIRST_SKILL("arbitraryArgs"), //More skills between the 2
FACTION1_LAST_SKILL("arbitraryArgs");
...
}
enum Faction2 {
FACTION2_FIRST_SKILL("arbitraryArgs"), //More skills between the 2
FACTION2_LAST_SKILL("arbitraryArgs");
...
}
String arbitraryField; //1 of many fields universal among both factionless and factioned skills
Skills(String arbitraryArgs) { //1 of many universal constructors
this.arbitraryField = arbitraryArgs;
}
void doUniversalThing() {
//Code here
}
}
When I try to use this implementation, I get errors telling me that the constructors and/or fields for the values in the inner enums don't exist. I tried copy pasting the constructors and fields into each individual inner enum, however that was both unreadable and unaccommodating to potential future skills which would not be attached to a faction. This simplified example doesn't even include all of the methods and alternate constructors that must be accessible to each skill. How could I implement this idea effectively and elegantly in a way that both supports skills which are a member of a faction and skills which are not, assuming that I could implement it at all? I tried my best to explain the intended results of the code, but if anything is still unclear then just let me know. Thank you.
Edit: The contents of Faction1 were requested, so in additon to me rewriting my initial code example to maybe give a better idea of my intentions, here's a few different ways I've tried Faction1. All were either erroneous or just not ideal.
Attempt 1:
public enum Skills {
FACTIONLESS_SKILL("arbitraryArgs"); //More skills than just this one
enum Faction1 {
FACTION1_FIRST_SKILL("arbitraryArgs"), //More skills between the 2
FACTION1_LAST_SKILL("arbitraryArgs");
}
String arbitraryField; //1 of many fields universal among both factionless and factioned skills
Skills(String arbitraryArgs) { //1 of many universal constructors
this.arbitraryField = arbitraryArgs;
}
}
My first attempt was just this, which gave me an error that The constructor Skills.Faction2(String) is undefined. I understand that this is due to Faction2 being its own class and unable to use a Skills constructor, which is why I then moved to my second attempt.
Attempt 2:
public enum Skills {
FACTIONLESS_SKILL("arbitraryArgs"); //More skills than just this one
enum Faction1 {
FACTION1_FIRST_SKILL("arbitraryArgs"), //More skills between the 2
FACTION1_LAST_SKILL("arbitraryArgs");
String arbitraryField; Duplicates of Skills fields
Faction1(String arbitraryArgs) { //Duplicate of Skills constructor
this.arbitraryField = arbitraryArgs;
}
}
String arbitraryField; //1 of many fields universal among both factionless and factioned skills
Skills(String arbitraryArgs) { //1 of many universal constructors
this.arbitraryField = arbitraryArgs;
}
}
This solution technically works, in that there are no errors. However, my issue with this solution is the insane amount of code duplication this causes in my non-reduced program. Every skill has numerous fields, constructors, and methods, whether the skill is assigned to a faction or not. There are also numerous factions that would need to be made. If I ever realized that a field or method or constructor was either unneeded and should be removed or needed and should be created, I would need to create or remove it from every faction individually. This is just honestly not something I want to do on a silly side project.
I haven't thought of any other way to create these inner enums, nor have I seen any in my research, so these are my only 2 implementations so far. I hope this clears things up a bit.
A brief OOPs class to begin with --
The Faction and Skill entities seem to have a has a relationship i.e., A Factions HAS A set of Skills. Also I will create an additional enum SkillName which again has a HAS A relation ship with Skill. So keeping these in mind you could arrange you enums like so --
public enum Faction {
FACTION1(new HashMap<SkillName, Skill>(){{
put(Skill.SNIPER_SHOT.skillName(), Skill.SNIPER_SHOT);
}}),
FACTION2(new HashMap<SkillName, Skill>(){{
put(Skill.JUDGEMENT.skillName(), Skill.JUDGEMENT);
}});
Map<SkillName, Skill> skills;
Faction(Map<SkillName, Skill> skills) {
this.skills = skills;
}
public Skill[] skills(){
return this.skills.values().toArray(new Skill[0]);
}
public Skill skill(SkillName name){
Skill skill = this.skills.get(name);
if(Objects.isNull(skill)){
throw new IllegalArgumentException("Invalid Skill name");
}
return skill;
}
}
enum SkillName {
SNIPER_SHOT("SNIPER_SHOT"),
JUDGEMENT("JUDGEMENT");
String value;
SkillName(String value){
this.value = value;
}
}
enum Skill {
SNIPER_SHOT(SkillName.SNIPER_SHOT, 0, 95, 5, new boolean[] {true, true, false, false}, new boolean[] {false, true, true, true}),
JUDGEMENT(SkillName.JUDGEMENT,-25, 85, 5, new boolean[] {true, true, false, false}, new boolean[] {true, true, true, true});
SkillName name;
Integer dmg;
Integer acc;
Integer crit;
boolean[] rank;
boolean[] target;
Skill(SkillName name, Integer dmg, Integer acc, Integer crit, boolean[] rank, boolean[] target) {
this.name = name;
this.dmg = dmg;
this.acc = acc;
this.crit = crit;
this.rank = rank;
this.target = target;
}
public SkillName skillName() {
return this.name;
}
}
Now you could access the skills and a specific skill like so, --
Faction.FACTION1.skills();
Faction.FACTION2.skills();
Faction.FACTION1.skill(SkillName.SNIPER_SHOT);
Faction.FACTION1.skill(SkillName.JUDGEMENT); // this should throw exception
Faction.FACTION2.skill(SkillName.SNIPER_SHOT); // this should throw exception
Faction.FACTION2.skill(SkillName.JUDGEMENT);
The access patterns are not exactly the same as you wanted, but these work pretty much to the same extent.
SIDE NOTE -
Not sure what type of game you are developing, but in most of the games, skill of players improve (i.e. skill properties change) and players acquire new skills as well. Hence the above setup will become very rigid as enums are immutable and you will not be able to scale this. Instead, what I would suggest is that you create classes for Factions and Skills instead of enums. This way you would be able to mutate them.
Just decided to upgrade to Java 9 to use Map.of(). Thank you all for your help!
Seems like you already found your solution, but here is something that is probably much easier to use.
import java.util.Arrays;
import java.util.List;
/** Enums. https://stackoverflow.com/questions/71517372 */
public class SOQ_20220406_0201
{
/**
*
* Main method.
*
* #param args commandline arguments, should they be needed.
*
*/
public static void main(String[] args)
{
enum Faction
{
F1,
F2,
F3,
ALL,
;
}
enum Skill
{
SKILL_1(Faction.F1, "arbitraryArgs"),
SKILL_2(Faction.F2, "arbitraryArgs"),
SKILL_3(Faction.F3, "arbitraryArgs"),
SKILL_ALL_CAN_USE(Faction.ALL, "arbitraryArgs"),
;
private final Faction faction;
private final String arbitraryArgs;
Skill(Faction faction, String arbitraryArgs)
{
this.faction = faction;
this.arbitraryArgs = arbitraryArgs;
}
public static List<Skill> fetchAllSkillsForFaction(final Faction faction)
{
return
Arrays.stream(values())
.parallel()
.filter(each -> each.faction == faction)
.toList()
;
}
}
System.out.println(Skill.fetchAllSkillsForFaction(Faction.F1));
}
}

Java class: limit instance variable to one of several possible values, depending on other instance variables

I am sorry for the vague question. I am not sure what I'm looking for here.
I have a Java class, let's call it Bar. In that class is an instance variable, let's call it foo. foo is a String.
foo cannot just have any value. There is a long list of strings, and foo must be one of them.
Then, for each of those strings in the list I would like the possibility to set some extra conditions as to whether that specific foo can belong in that specific type of Bar (depending on other instance variables in that same Bar).
What approach should I take here? Obviously, I could put the list of strings in a static class somewhere and upon calling setFoo(String s) check whether s is in that list. But that would not allow me to check for extra conditions - or I would need to put all that logic for every value of foo in the same method, which would get ugly quickly.
Is the solution to make several hundred classes for every possible value of foo and insert in each the respective (often trivial) logic to determine what types of Bar it fits? That doesn't sound right either.
What approach should I take here?
Here's a more concrete example, to make it more clear what I am looking for. Say there is a Furniture class, with a variable material, which can be lots of things, anything from mahogany to plywood. But there is another variable, upholstery, and you can make furniture containing cotton of plywood but not oak; satin furniture of oak but not walnut; other types of fabric go well with any material; et cetera.
I wouldn't suggest creating multiple classes/templates for such a big use case. This is very opinion based but I'll take a shot at answering as best as I can.
In such a case where your options can be numerous and you want to keep a maintainable code base, the best solution is to separate the values and the logic. I recommend that you store your foo values in a database. At the same time, keep your client code as clean and small as possible. So that it doesn't need to filter through the data to figure out which data is valid. You want to minimize dependency to data in your code. Think of it this way: tomorrow you might need to add a new material to your material list. Do you want to modify all your code for that? Or do you want to just add it to your database and everything magically works? Obviously the latter is a better option. Here is an example on how to design such a system. Of course, this can vary based on your use case or variables but it is a good guideline. The basic rule of thumb is: your code should have as little dependency to data as possible.
Let's say you want to create a Bar which has to have a certain foo. In this case, I would create a database for BARS which contains all the possible Bars. Example:
ID NAME FOO
1 Door 1,4,10
I will also create a database FOOS which contains the details of each foo. For example:
ID NAME PROPERTY1 PROPERTY2 ...
1 Oak Brown Soft
When you create a Bar:
Bar door = new Bar(Bar.DOOR);
in the constructor you would go to the BARS table and query the foos. Then you would query the FOOS table and load all the material and assign them to the field inside your new object.
This way whenever you create a Bar the material can be changed and loaded from DB without changing any code. You can add as many types of Bar as you can and change material properties as you goo. Your client code however doesn't change much.
You might ask why do we create a database for FOOS and refer to it's ids in the BARS table? This way, you can modify the properties of each foo as much as you want. Also you can share foos between Bars and vice versa but you only need to change the db once. cross referencing becomes a breeze. I hope this example explains the idea clearly.
You say:
Is the solution to make several hundred classes for every possible
value of foo and insert in each the respective (often trivial) logic
to determine what types of Bar it fits? That doesn't sound right
either.
Why not have separate classes for each type of Foo? Unless you need to define new types of Foo without changing the code you can model them as plain Java classes. You can go with enums as well but it does not really give you any advantage since you still need to update the enum when adding a new type of Foo.
In any case here is type safe approach that guarantees compile time checking of your rules:
public static interface Material{}
public static interface Upholstery{}
public static class Oak implements Material{}
public static class Plywood implements Material{}
public static class Cotton implements Upholstery{}
public static class Satin implements Upholstery{}
public static class Furniture<M extends Material, U extends Upholstery>{
private M matrerial = null;
private U upholstery = null;
public Furniture(M matrerial, U upholstery){
this.matrerial = matrerial;
this.upholstery = upholstery;
}
public M getMatrerial() {
return matrerial;
}
public U getUpholstery() {
return upholstery;
}
}
public static Furniture<Plywood, Cotton> cottonFurnitureWithPlywood(Plywood plywood, Cotton cotton){
return new Furniture<>(plywood, cotton);
}
public static Furniture<Oak, Satin> satinFurnitureWithOak(Oak oak, Satin satin){
return new Furniture<>(oak, satin);
}
It depends on what you really want to achieve. Creating objects and passing them around will not magically solve your domain-specific problems.
If you cannot think of any real behavior to add to your objects (except the validation), then it might make more sense to just store your data and read them into memory whenever you want. Even treat rules as data.
Here is an example:
public class Furniture {
String name;
Material material;
Upholstery upholstery;
//getters, setters, other behavior
public Furniture(String name, Material m, Upholstery u) {
//Read rule files from memory or disk and do all the checks
//Do not instantiate if validation does not pass
this.name = name;
material = m;
upholstery = u;
}
}
To specify rules, you will then create three plain text files (e.g. using csv format). File 1 will contain valid values for material, file 2 will contain valid values for upholstery, and file 3 will have a matrix format like the following:
upholstery\material plywood mahogany oak
cotton 1 0 1
satin 0 1 0
to check if a material goes with an upholstery or not, just check the corresponding row and column.
Alternatively, if you have lots of data, you can opt for a database system along with an ORM. Rule tables then can be join tables and come with extra nice features a DBMS may provide (like easy checking for duplicate values). The validation table could look something like:
MaterialID UpholsteryID Compatability_Score
plywood cotton 1
oak satin 0
The advantage of using this approach is that you quickly get a working application and you can decide what to do as you add new behavior to your application. And even if it gets way more complex in the future (new rules, new data types, etc) you can use something like the repository pattern to keep your data and business logic decoupled.
Notes about Enums:
Although the solution suggested by #Igwe Kalu solves the specific case described in the question, it is not scalable. What if you want to find what material goes with a given upholstery (the reverse case)? You will need to create another enum which does not add anything meaningful to the program, or add complex logic to your application.
This is a more detailed description of the idea I threw out there in the comment:
Keep Furniture a POJO, i.e., just hold the data, no behavior or rules implemented in it.
Implement the rules in separate classes, something along the lines of:
interface FurnitureRule {
void validate(Furniture furniture) throws FurnitureRuleException;
}
class ValidMaterialRule implements FurnitureRule {
// this you can load in whatever way suitable in your architecture -
// from enums, DB, an XML file, a JSON file, or inject via Spring, etc.
private Set<String> validMaterialNames;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
if (!validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial());
}
}
class UpholsteryRule implements FurnitureRule {
// Again however suitable to implement/config this
private Map<String, Set<String>> validMaterialsPerUpholstery;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
Set<String> validMaterialNames = validMaterialsPerUpholstery.get(furniture.getUpholstery();
if (validMaterialNames != null && !validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial() + " for upholstery " + furniture.getUpholstery());
}
}
// and more complex rules if you need to
Then have some service along the lines of FurnitureManager. It's the "gatekeeper" for all Furniture creation/updates:
class FurnitureManager {
// configure these via e.g. Spring.
private List<FurnitureRule> rules;
public void updateFurniture(Furniture furniture) throws FurnitureRuleException {
rules.forEach(rule -> rule.validate(furniture))
// proceed to persist `furniture` in the database or whatever else you do with a valid piece of furniture.
}
}
material should be of type Enum.
public enum Material {
MAHOGANY,
TEAK,
OAK,
...
}
Furthermore you can have a validator for Furniture that contains the logic which types of Furniture make sense, and then call that validator in every method that can change the material or upholstery variable (typically only your setters).
public class Furniture {
private Material material;
private Upholstery upholstery; //Could also be String depending on your needs of course
public void setMaterial(Material material) {
if (FurnitureValidator.isValidCombination(material, this.upholstery)) {
this.material = material;
}
}
...
private static class FurnitureValidator {
private static boolean isValidCombination(Material material, Upholstery upholstery) {
switch(material) {
case MAHOGANY: return upholstery != Upholstery.COTTON;
break;
//and so on
}
}
}
}
We often are oblivious of the power inherent in enum types. The Java™ Tutorials clearly states "you should use enum types any time you need to represent a fixed set of constants."
How do you simply make the best of enum in resolving the challenge you presented? - Here goes:
public enum Material {
MAHOGANY( "satin", "velvet" ),
PLYWOOD( "leather" ),
// possibly many other materials and their matching fabrics...
OAK( "some other fabric - 0" ),
WALNUT( "some other fabric - 0", "some other fabric - 1" );
private final String[] listOfSuitingFabrics;
Material( String... fabrics ) {
this.listOfSuitingFabrics = fabrics;
}
String[] getListOfSuitingFabrics() {
return Arrays.copyOf( listOfSuitingFabrics );
}
public String toString() {
return name().substring( 0, 1 ) + name().substring( 1 );
}
}
Let's test it:
public class TestMaterial {
for ( Material material : Material.values() ) {
System.out.println( material.toString() + " go well with " + material.getListOfSuitingFabrics() );
}
}
Probably the approach I'd use (because it involves the least amount of code and it's reasonably fast) is to "flatten" the hierarchical logic into a one-dimensional Set of allowed value combinations. Then when setting one of the fields, validate that the proposed new combination is valid. I'd probably just use a Set of concatenated Strings for simplicity. For the example you give above, something like this:
class Furniture {
private String wood;
private String upholstery;
/**
* Set of all acceptable values, with each combination as a String.
* Example value: "plywood:cotton"
*/
private static final Set<String> allowed = new HashSet<>();
/**
* Load allowed values in initializer.
*
* TODO: load allowed values from DB or config file
* instead of hard-wiring.
*/
static {
allowed.add("plywood:cotton");
...
}
public void setWood(String wood) {
if (!allowed.contains(wood + ":" + this.upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
}
public void setUpholstery(String upholstery) {
if (!allowed.contains(this.wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.upholstery = upholstery;
}
public void setMaterials(String wood, String upholstery) {
if (!allowed.contains(wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
this.upholstery = upholstery;
}
// getters
...
}
The disadvantage of this approach compared to other answers is that there is no compile-time type checking. For example, if you try to set the wood to plywoo instead of plywood you won’t know about your error until runtime. In practice this disadvantage is negligible since presumably the options will be chosen by a user through a UI (or through some other means), so you won’t know what they are until runtime anyway. Plus the big advantage is that the code will never have to be changed so long as you’re willing to maintain a list of allowed combinations externally. As someone with 30 years of development experience, take my word for it that this approach is far more maintainable.
With the above code, you'll need to use setMaterials before using setWood or setUpholstery, since the other field will still be null and therefore not an allowed combination. You can initialize the class's fields with default materials to avoid this if you want.

saving only doubledigit numbers into my attribute

I got a task for a Season Object which can only save doubledigit integer numbers as the season number.
How can I initialize the value properly so it will only store doubledigit numbers?
I'm not allowed to use methods or my constructor for that.
the only possible solution I found (even though it would be dumb) is to use an enum from 1 to 99.
Is this really the solution? I'm also not allowed to use API classes for that.
Edit:
public class Season {
String name;
Series series;
int seasonNumber;
public Season () { }
}
I didn't post the code on purpose cause it isn't anything that will help
Edit2: (Tl;Dr of the Task)
The Task is to create a Series, Season and Episode Object. Series and Episode aren't of interest as for this question. The Season Object is defined as you can see in the code above.
The overall conditions are as following:
- primitive datatypes, String, enum are allowed and every class I wrote myself.
- no API classes are allowed.
- methods aren't needed.
- constructor isn't allowed to modify my number with regEx or anything like that
This is the best solution I can come up with:
public Season(int seasonNumber) {
if (seasonNumber < 1 || seasonNumber > 99) {
throw new IllegalArgumentException("Value between 1 and 99 (both inclusive) required. Found + " seasonNumber);
}
this.seasonNumber = seasonNumber;
}
I am not using a method, because the logic is all in the constructor. Though I suspect the person who gave you this hasn't got his point across with the assignment texts.
If you want the season number returned as 01, 02, etc., you could create a method that returns a String, instead of an int:
public String getSeasonNumber() {
if (seasonNumber < 10) {
return "0" + seasonNumber;
} else {
return seasonNumber;
}
}

Java Enum.valueOf() efficiency when value does not exist

Which would you consider more efficient?
The use of 'WeekDay' is just an example:
public enum WeekDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
}
Loop through and verify day string first:
public void parseString(String line) {
String[] tokens = line.split();
String day = tokens[1]; // day 'should' always be a weekday
if (isValidWeekDay(day)) {
WeekDay weekDay = WeekDay.valueOf(day); // won't throw exception
...
} else {
throw new InvalidWeekDayException(day); // subclass of RuntimeException
}
}
private boolean isValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return true;
}
return false;
}
Or since in 99.99% of cases, day will be correct:
public void parseString(String line) {
String[] tokens = line.split();
String day = tokens[1]; // day 'should' always be a weekday
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day, e);
}
}
Update:
To clarify, the input string will come from a client application, rather than a user. So in other words, it would be a bug to recieve a non workday in this example.
As has been commented, you will have to profile to find out for sure. Even in your own parsing approach, you can make it faster by returning the enum when you parse the list.
private WeekDay getValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return weekDay;
}
return null;
}
Unless this is a time critical piece of an application, I wouldn't worry about it in either case and simply take the most readable approach. I think that would be using the WeekDay.valueOf() method.
If you would rather not have to deal with exceptions, then create a Map of your values within the enum and effectively do the equivalent of valueOf() from a lookup which returns null if it is not found.
public enum WeekDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
private static Map<String, WeekDay> valueMap;
public static WeekDay getValue(String possibleName)
{
if (valueMap == null)
{
valueMap = new HashMap<String, WeekDay>();
for(WeedDay day: values())
valueMap.put(day.toString(), day);
}
return valueMap.get(possibleName);
}
}
This is effectively what the valueOf() method is doing anyway, except it throws the IllegalArgumentException when it is not found. This approach will simply return null, thus not generating the stacktrace.
What is the performance concern about the 2nd approach? Catching an exception like that costs almost nothing. Using exceptions for normal control flow is generally a bad idea from a design perspective, the days where this was a performance consideration are long gone. In a debugger, using exceptions as significant control operations will slow things down by a factor of about 10. But this gets optimized by the JIT and there is no measurable impact in production.
These numbers are based on experience with an evaluation I did of the zxing project, which uses exceptions for all sorts of flow control. When I first saw it, I was horrified. I still think it's not the best design, but I did quite a bit of testing and can say with a good bit of confidence that it had no real impact on performance. And this is an algorithm that was using exceptions all over the place for flow control. Your situation, where the exception will only get thrown in highly exceptional circumstances, is a non issue.
Edit: I've had a downvote or two on my answer, and I want to make sure that I'm super clear on what I'm saying: I do not think that it's a good idea to use exceptions for normal control flow. Just because performance is not a good argument for not using exceptions this way doesn't mean that there aren't other, perfectly valid reasons (such as readability, testability, extendability). In the case of the OP, the use of an exception is absolutely called for, and definitely wouldn't cause any sort of performance issue.
I know its an old post, but I believe following result will be still interesting. I run 10000000 tests to find an element in enum ENUM {FIRST, SECOND, THIRD, FOURTH, LAST} using JDK 1.8. The table below shows time required by simple loop and valueOf().
text loop valueOf ratio
------------------------------
"FIRST" 121 65 186%
"LAST" 188 57 330%
"foo" 155 8958 1.7%
Conclusion - I wouldn't use valueOf() if I expect values not matching enum.
If your question is really about the efficiency of searching among 7 item you have already wasted too much time on it. Even the fastest search algorithms yield zero or negative benefits until N > 15 or so, other than the O(1) one.
Store the valid strings in a HashSet, and decide whether a string is a valid day or not based on Set.contains(...).
The set can be a static final Set, and you can wrap in an unmodifiable for good measure:
private static final Map<String> WEEKDAY_STRINGS;
static {
HashSet<String> set = new HashSet();
for (WeekDay d : WeekDay.values()) {
set.add(d.toString());
}
WEEKDAY_STRINGS = Collections.unmodifiableSet(set);
}
The loop doesn't do anything that calling valueof doesn't, they have the same functionality : checking whether your string is valid enum. What do you think you gain from the first option ?
The second option is best:
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day);
}
Or you could create a lookup of enum values inside your enum when the class first loads(see static modifier) and validate using get() as shown below:
private String dayName;
private static final Map<String,Weekday> lookup = new HashMap<String, Weekday>();
static{
for (Weekday day: values()){
lookup.put(day.dayName, d);
}
}
public static Weekday get(String _name){
return lookup.get(_name);
}
Let me know if you need more details

Implementing a bitfield using java enums

I maintain a large document archive and I often use bit fields to record the status of my documents during processing or when validating them. My legacy code simply uses static int constants such as:
static int DOCUMENT_STATUS_NO_STATE = 0
static int DOCUMENT_STATUS_OK = 1
static int DOCUMENT_STATUS_NO_TIF_FILE = 2
static int DOCUMENT_STATUS_NO_PDF_FILE = 4
This makes it pretty easy to indicate the state a document is in, by setting the appropriate flags. For example:
status = DOCUMENT_STATUS_NO_TIF_FILE | DOCUMENT_STATUS_NO_PDF_FILE;
Since the approach of using static constants is bad practice and because I would like to improve the code, I was looking to use Enums to achieve the same. There are a few requirements, one of them being the need to save the status into a database as a numeric type. So there is a need to transform the enumeration constants to a numeric value. Below is my first approach and I wonder if this is the correct way to go about this?
class DocumentStatus{
public enum StatusFlag {
DOCUMENT_STATUS_NOT_DEFINED(1<<0),
DOCUMENT_STATUS_OK(1<<1),
DOCUMENT_STATUS_MISSING_TID_DIR(1<<2),
DOCUMENT_STATUS_MISSING_TIF_FILE(1<<3),
DOCUMENT_STATUS_MISSING_PDF_FILE(1<<4),
DOCUMENT_STATUS_MISSING_OCR_FILE(1<<5),
DOCUMENT_STATUS_PAGE_COUNT_TIF(1<<6),
DOCUMENT_STATUS_PAGE_COUNT_PDF(1<<7),
DOCUMENT_STATUS_UNAVAILABLE(1<<8);
private final long statusFlagValue;
StatusFlag(long statusFlagValue) {
this.statusFlagValue = statusFlagValue;
}
public long getStatusFlagValue(){
return statusFlagValue;
}
}
/**
* Translates a numeric status code into a Set of StatusFlag enums
* #param numeric statusValue
* #return EnumSet representing a documents status
*/
public EnumSet<StatusFlag> getStatusFlags(long statusValue) {
EnumSet statusFlags = EnumSet.noneOf(StatusFlag.class);
StatusFlag.each { statusFlag ->
long flagValue = statusFlag.statusFlagValue
if ( (flagValue&statusValue ) == flagValue ) {
statusFlags.add(statusFlag);
}
}
return statusFlags;
}
/**
* Translates a set of StatusFlag enums into a numeric status code
* #param Set if statusFlags
* #return numeric representation of the document status
*/
public long getStatusValue(Set<StatusFlag> flags) {
long value=0;
flags.each { statusFlag ->
value|=statusFlag.getStatusFlagValue()
}
return value;
}
public static void main(String[] args) {
DocumentStatus ds = new DocumentStatus();
Set statusFlags = EnumSet.of(
StatusFlag.DOCUMENT_STATUS_OK,
StatusFlag.DOCUMENT_STATUS_UNAVAILABLE);
assert ds.getStatusValue( statusFlags )==258 // 0000.0001|0000.0010
long numericStatusCode = 56;
statusFlags = ds.getStatusFlags(numericStatusCode);
assert !statusFlags.contains(StatusFlag.DOCUMENT_STATUS_OK);
assert statusFlags.contains(StatusFlag.DOCUMENT_STATUS_MISSING_TIF_FILE);
assert statusFlags.contains(StatusFlag.DOCUMENT_STATUS_MISSING_PDF_FILE);
assert statusFlags.contains(StatusFlag.DOCUMENT_STATUS_MISSING_OCR_FILE);
}
}
Instead of defining constructor parameters, you could simply use the internal ordinal() value to calculate this.
public enum StatusFlag {
DOCUMENT_STATUS_NOT_DEFINED,
DOCUMENT_STATUS_OK,
DOCUMENT_STATUS_MISSING_TID_DIR,
DOCUMENT_STATUS_MISSING_TIF_FILE,
DOCUMENT_STATUS_MISSING_PDF_FILE,
DOCUMENT_STATUS_MISSING_OCR_FILE,
DOCUMENT_STATUS_PAGE_COUNT_TIF,
DOCUMENT_STATUS_PAGE_COUNT_PDF,
DOCUMENT_STATUS_UNAVAILABLE;
public long getStatusFlagValue(){
return 1 << this.ordinal();
}
}
Please note that now you should abstain from reordering, inserting (other than at the end) or deleting entries, otherwise the flag values will change, and the meaning of your database contents will change.
your approach is exactly the way to do it.
A slightly better way would be to store the result of 1 << this.ordinal() in a field when
the enum values are constructed. This way, you don't have to provide each value manually, and the flag is only computed once.
public enum StatusFlag {
DOCUMENT_STATUS_NOT_DEFIND,
DOCUMENT_STATUS_OK,
DOCUMENT_STATUS_MISSING_TID_DIR,
DOCUMENT_STATUS_MISSING_TIF_FILE,
DOCUMENT_STATUS_MISSING_PDF_FILE,
DOCUMENT_STATUS_MISSING_OCR_FILE,
DOCUMENT_STATUS_PAGE_COUNT_TIF,
DOCUMENT_STATUS_PAGE_COUNT_PDF,
DOCUMENT_STATUS_UNAVAILABLE;
public final int flag;
StatusFlag() {
this.flag = 1 << this.ordinal();
}
}
**Update:** This is an old answer from back when I did not have much Java experience.
I no longer think my answer is valid, as this approach couples the value of the flag to the ordering or the enum values, which is bad: if the order is changed or enum values are removed, this will affect the flags of other enum values, which can have unforeseen consequences.
These days, I would use the approach used in the question (manually provide the value of the flag via a constructor parameter) as it is more maintainable:
public enum StatusFlag {
DOCUMENT_STATUS_NOT_DEFINED(0),
DOCUMENT_STATUS_OK(1),
DOCUMENT_STATUS_MISSING_TID_DIR(2),
DOCUMENT_STATUS_MISSING_TIF_FILE(3),
DOCUMENT_STATUS_MISSING_PDF_FILE(4),
DOCUMENT_STATUS_MISSING_OCR_FILE(5),
DOCUMENT_STATUS_PAGE_COUNT_TIF(6),
DOCUMENT_STATUS_PAGE_COUNT_PDF(7),
DOCUMENT_STATUS_UNAVAILABLE(8);
public final int flag;
StatusFlag(int id) {
this.flag = 1 << id;
}
}
Don't give your enums values. Use an EnumSet to combine them, and use Enum.ordinal() when persisting in order to convert to/from a single integer. You might also find Class.getEnumConstants() useful when reconstructing the set from the integer.
I have made a complete library for this problem:
http://claude-martin.ch/enumbitset/
The main goal was to store sets of enum types in bitfields. But it also supports other types.
With this you would not need any extra methods like your "getStatusFlags()". It can be used on any existing enum type simply by adding the interface EnumBitSetHelper (it is used like a "trait").
Each enum constant can then create an "EnumBitSet" which has all methods of Java's EnumSet and BitSet.
Then you can work with these sets of enum constants and convert them to bitfield values.
It supports many formats such as BigInteger and long to easily store the value into a bit field.
But note that this only works with Java version 8 and newer.

Categories