How to disable some enum and keep the enum value? - java

I wrote a library
This library accept the limited options and print the related string.
public class Lib {
public enum Num {
ZERO,
ONE,
TWO,
THREE
}
public static void main(String[] args) {
Lib obj = new Lib();
obj.print(Num.ONE);
}
public void print(Num num) {
switch (num) {
case ZERO:
System.out.println("ZERO is "+Num.ZERO.ordinal());
break;
case ONE:
System.out.println("ONE is "+Num.ONE.ordinal());
break;
case TWO:
System.out.println("TWO is "+Num.TWO.ordinal());
break;
case THREE:
System.out.println("THREE is "+Num.THREE.ordinal());
break;
default:
break;
}
}
}
In the new version, I will disable option ONE and TWO
public enum Num {
ZERO,
//ONE,
//TWO,
THREE
}
How can I keep the correct values after I disabled the options?

It is not clear what you are asking. If you change any piece of code and thereby "remove" "names" that formerly existed ... than of course, any "reference" to any of the deleted elements is ... first of all: broken.
In case of an enum, you might prefer to not rely on build-in ordinals; instead you could go for this:
enum Whatever {
ONE(1), TWO(2);
private final int value;
private Whatever(value) {
this.value = value;
}
public int getValue() { return value }
But you have to be really careful here. For example, if you are persisting enum objects (into some sort of database for example) then any such change (adding or removing enum "values") will lead to incompatibilities!

I am not sure of what you want to do, but for example you can do this:
public enum Num {
ZERO,
ONE,
TWO,
THREE
}
switch (num) {
case ZERO:
System.out.println("ZERO is "+Num.ZERO.ordinal());
break;
case THREE:
System.out.println("ZERO is "+Num.THREE.ordinal());
break;
case One:
case Two:
default:
break;

You might be disable some of enum now onward and keep stored as it is. To support both the things, you should have a method that returns list of enum that will populate on UI. I.E. List getPopulatedOnUi(). That contains those enum list that you needed.
Don't remove from definition itself. keep as it is. because that will throw error for existing as it might be stored into database.

You can modify the print() method as below: Instead of switch, you can use for loop and make the code little bit generic. Now, even when your enum values changes, you need not to make any changes in this code.
It will handle the case , If you disable some enum values in future.
public void print(Num num) {
for(Num n : Num.values()) {
if(n == num) {
System.out.println(n.name()+ " is " + n.ordinal());
break;
}
}
}

Related

Real life implementation of Enums

I have recently learnt that Enums are kind of data types just like int, char etc. But in Enums we can define our on data types. But my question what is the necessity for user defined data types. I would be helpful if an example of real world scenario is provided.
An enum type is a special data type that enables for a variable to be
a set of predefined constants.
Here is some code that shows you how to use the Day enum defined above:
public class EnumTest {
Day day;
public EnumTest(Day day) {
this.day = day;
}
public void tellItLikeItIs() {
switch (day) {
case MONDAY:
System.out.println("Mondays are bad.");
break;
case FRIDAY:
System.out.println("Fridays are better.");
break;
case SATURDAY: case SUNDAY:
System.out.println("Weekends are best.");
break;
default:
System.out.println("Midweek days are so-so.");
break;
}
}
public static void main(String[] args) {
EnumTest firstDay = new EnumTest(Day.MONDAY);
firstDay.tellItLikeItIs();
EnumTest thirdDay = new EnumTest(Day.WEDNESDAY);
thirdDay.tellItLikeItIs();
EnumTest fifthDay = new EnumTest(Day.FRIDAY);
fifthDay.tellItLikeItIs();
EnumTest sixthDay = new EnumTest(Day.SATURDAY);
sixthDay.tellItLikeItIs();
EnumTest seventhDay = new EnumTest(Day.SUNDAY);
seventhDay.tellItLikeItIs();
}
}
The output is:
Mondays are bad.
Midweek days are so-so.
Fridays are better.
Weekends are best.
Weekends are best.
for more details check this tutorial.
User data types are like building blocks. We have the limited number of such standard blocks (e.g. primitive types), therefore, we need to expand them by building our own classes. Enum is a class with predefined values that cannot be changed.
For example,
public enum ProfessionType { DOCTOR, MANAGER, SELLER; }
We guarantee that it will create only one instance of DOCTOR, MANAGER and so on. Imagine, we are going to create a doctor type manually (in this case, ProfessionType is a class)
ProfessionType doctor1 = new ProfessionType("doctor");
ProfessionType doctor2 = new ProfessionType("doctor");
Which one is better? Am I a doctor of doctor1 type or of the second one?
Lets say we are asked to sum the position number of each alphabet of a sentence that was sent to a function
Example:
A=1,B=2,C=3....so on
so instead of using switch each char in loop and then add its value we could use Enum here , Because all values are incremented by 1 by default
public enum Alpha
{
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
}
// based on the input
public static int Count(string name="")
{
int sum = 0;
foreach (char item in name)
{
if (!string.IsNullOrWhiteSpace(item.ToString()))
sum += (int)Enum.Parse(typeof(Alpha), item.ToString().ToUpper());
}
return sum;
}

Regex if-statements mixed with switch statements

I am working with some Java code that is comprised of a switch statement comparing strings. There are about 5 cases before learning that more needed to be added.
In fact I would need to add 64 more cases (4 groups of 16 similarly spelled values) and due to the nature of the strings was hoping to use regex to not need so many statements. For example, the first group of possible values is "Section ## Stuff", the second group "Section ## Stuff XYZ", and so on; where the ## is any number between 1 and 16.
To clarify, instead of adding a case for each string, I wanted to regex out the type, and then call the appropriate function, etc.
While this is all working correctly, I am worried that it will be hard for another developer to make sense of what is happening, as I have essentially combined regex if-statements and switch statements. I also cannot stand having very large switch statement lists.
What is the better option (readability vs eloquence, etc.), and is it possible to somehow use regex with my switch statement? Also, I don't think there would be any significant performance hit, but if there is, it would be nice to know. :)
Code below is an example as I cannot provide the real code.
What I want to do:
if (str.matches("Section ([1-9]|1[0-6]) Stuff") {
//do something with the number provided in string
} else if (str.matches("Section ([1-9]|1[0-6]) Stuff 2") {
//do something else with the number provided in the string
} else {
switch (str) {
case PARAM_VALUE_1:
doSomething1();
break;
case PARAM_VALUE_2:
doSomething2();
break;
...
...
default:
break;
}
}
OR -
switch (str) {
case PARAM_VALUE_1:
doSomething1();
break;
case PARAM_VALUE_2:
doSomething2();
break;
...
...
case "Section 1 Stuff":
//do something for section 1
break;
case "Section 2 Stuff":
//do something for section 2
break;
...
... (64 cases later)
default:
break;
}
}
Note: I cannot redesign the way the string comes in; it comes from another subsystem and it is what it is.
Thanks for your help!
For this case, you might consider using Java enums, exploiting their overriding functionality.
enum MyEnum {
SectionOne("Section ([1-9]|1[0-6]) Stuff") {
#Override
public void doSomething() {
// implementation for section one when regex matches
}
}, SectionTwo("Section ([1-9]|1[0-6]) Stuff 2") {
#Override
public void doSomething() {
// implementation for section two when regex matches
}
}, Param1("ParamValue1") {
#Override
public void doSomething() {
// implementation for param 1
}
}, Param2("ParamValue2") {
#Override
public void doSomething() {
// implementation for param 2
}
};
private final Pattern regex;
private MyEnum(String strRegex) {
this.regex = Pattern.compile(strRegex);
}
public abstract void doSomething();
public static MyEnum valueFor(String value) {
for (MyEnum myEnum : MyEnum.values()) {
if(myEnum.regex.matcher(value).matches()) {
return myEnum;
}
}
return null;
}
}
You can see the IDEOne demo.

Returning switch capable value based on String

Not sure how I'm going to attack this.
Basically what I have is input of varying length, one or multiple times, that will cause an action. It being from typed input, file etc.
I have no idea on by what and how to tackle this. Would it be best to have a function returning an int that correspond to an public static final int FOO = 1;, an enum, an other way?
What I have as of now is a series of if statements as in:
if (str.equals("foo") || str.equals("F")) {
blah;
} else if (str.equals("beach")) {
more blah;
}
Is this good as any, or is there a better way? Have had a peek at enum but seems like that is more to it then in e.g. C. This is probably wrong, but would it be something in the direction of this?
class Mother
{
HappyCamping() {
switch (ValInput(str)) {
case FOO: do fo; break;
case BAR: do bar; break;
case BAZ: do fo bar: break
...
}
private enum ValInput(String str)
{
FOO("foo"), BAR("bar"), BAZ("baz");
private int value;
private ValInput(String str) {
if (str.equals("blah"))
this.value = 1;
...
}
}
}
Point being having a cleaner approach and separate out the "parsing" from the main routine. What would be a good way here?
One approach would be to write a parser that returns tokens. The tokens could be represented by ints or Enums. That modularizes your code in a way you suggest you want.
The other way is to use enums.
public enum Token {
FOO("foo", "f"),
BAR("bar", "b");
private String keyword;
private String abbreviation;
private Token(String keyword, String abbreviation) {
this.keyword = keyword;
this.abbreviation = abbreviation;
}
public String getKeyword() {
return this.keyword;
}
public String getAbbreviation() {
return this.abbreviation;
}
public static Token valueOf(String s) {
for (Token token : values()) {
if (token.getKeyword().equals(s) || token.getAbbreviation().equals(s)) {
return token;
}
}
throw new IllegalArgumentException("No such keyword: " + s);
}
}
Then you can do something like:
switch (Token.valueOf(inputString)) {
case BAR : doBarStuff(); return;
case FOO : doFooStuff(); return;
}
Is this good as any, or is there a better way? Have had a peek at enum but seems like that is more to it then in e.g. C. This is probably wrong, but would it be something in the direction of this?
Then go learn how enum works. Don't avoid a feature that may solve your problem just because it has more features. Chances are your design will want to make use of Java-style enums if you want a fixed set of actions.
enum Action { CLICK("click"), CLEAR("erase"); }
etc. is a good start.
Java (I think since 6, possibly 7) also supports switch taking strings instead of integer or enum values.
Not sure that I understand the entire problem, but you can convert a string to an enum easily in Java.
If the entry strings are limited and predefined, and you want to parse it as an enum using
EnumType.valueOf("foo")
I recommend reading on Java enums, they are quite powerful compared to C enums.
In Java 7 you can use String in a switch expression. Refer to this article:
switch (str) {
case "blah":
// some action
break;
case "beach":
// another blah
break;
default:
// default action
break;
}
Your if statements seems the most logical way to tackle this problem. No need to make your life complex, just keep it simple. Any other method has trade offs and complexity.
Consider using a Map and the command pattern as shown here. You can hide all map a keyword to functionality and never have to use an if or switch.

Switch on EnumSet

The old way, if we wanted to switch on some complicated bitmask, we could easily do it like this (a random example from the top of my head just to demonstrate the issue):
private static final int MAN = 0x00000001;
private static final int WOMAN = 0x00000002;
// ...alive, hungry, blind, etc.
private static final int DEAD = 0xFF000000;
public void doStuff(int human) {
switch (human) {
case MAN | DEAD:
// do something
break;
// more common cases
}
}
Nowadays, since we use enums and EnumSets, I'd sometimes like to do a similar thing:
enum Human {
MAN, WOMAN, DEAD; // etc.
}
public void doStuff(EnumSet human) {
switch (human) {
case Human.MAN | Human.DEAD:
// do something
break;
// more common cases
}
}
which doesn't work, because we can only switch on an int, enum or String value. At this point, I realized it can't be done, even though that enum values are basically just hidden integers. But I like to dig around and the feature looks very useful, so:
private static final EnumSet<Human> DEAD_MAN = EnumSet.of(Human.MAN, Human.DEAD);
public void doStuff(EnumSet human) {
switch (human) {
case DEAD_MAN:
// do something
break;
// more common cases
}
}
Still no luck. Knowing the trick for switch on Strings and that EnumSets are actually 64-bit fields (or arrays of them), I would also try:
switch (human.hashCode()) {
case (Human.MAN.hashCode() | Human.DEAD.hashCode()):
// do something
break;
// more common cases
}
thinking that when the Human hashCode() would be properly implemented to give consistent results, it could work. Nope:
java.lang.Error: Unresolved compilation problem: case expressions must be constant expressions
Now, I wonder why there's no possibility to do this. I always thought of enums and EnumSets in Java like a proper replacement for those old-school bitfields, but here it seems that the new ways can't handle more complicated cases.
The right solution kind of sucks compared to any of the switch possibilities:
public void doStuff(EnumSet human) {
if (human.contains(Human.MAN) && human.contains(Human.DEAD)) {
// do something
} else {
// more common cases
}
}
In particular, since the introduction of switch on Strings, I believe there are at least two possible implementations of switch on EnumSets:
In the case (Human.MAN | Human.DEAD) expressions, simple use a compile-time type check and ordinal() instead of the enums themselves.
Using the same trick as for Strings.
At compile time, compute the hashCode() of the name of the enum values (and possibly something additional - the number of values in enum, the ordinal() etc. - everything is static and constant from the compile time on). Yes, this would mean to change the hashCode() either of the EnumSet class or the Enum class.
use instead of the enums themselves
Now, is there any serious obstacle I didn't take into count (I can come up with a few, all can be easily overcame) that would render this impossible to implement easily? Or am I right that this would indeed be possible, but not desirable enough for Oracle to implement it, because it is not used so often?
Also, let me state that this is a purely academic question possibly without a good answer (don't know, I wouldn't ask otherwise). I might make it community wiki if it proves to be unanswerable. However, I couldn't find an answer (or even anyone discussing it) anywhere, so here it goes.
In Java & Object Oriented world you would have class with setters and getters on an Object and you would use those
public void doStuff(Human human) {
if(human.isDead()) {
if(human.isMale()) {
// something
} else if (human.isFemale()) {
// something else
} else {
// neither
}
}
}
Note: switch is not a good idea because it only takes exact matches. e.g. case MAN | DEAD: will not match MAN | HUNGRY | DEAD unless you only want to match those who were not hungry before they died. ;)
I will see your "absolutely sufficient" benchmark and raise you another flawed benchmark which "shows" it takes a fraction of a clock cycle (in cause you are wondering, that is hard to believe)
public static void main(String... args) {
Human human = new Human();
human.setMale(true);
human.setDead(true);
for(int i=0;i<5;i++) {
long start = System.nanoTime();
int runs = 100000000;
for(int j=0;j< runs;j++)
doStuff(human);
long time = System.nanoTime() - start;
System.out.printf("The average time to doStuff was %.3f ns%n", (double) time / runs);
}
}
public static void doStuff(Human human) {
if (human.isDead()) {
if (human.isMale()) {
// something
} else if (human.isFemale()) {
// something else
} else {
// neither
}
}
}
static class Human {
private boolean dead;
private boolean male;
private boolean female;
public boolean isDead() {
return dead;
}
public boolean isMale() {
return male;
}
public boolean isFemale() {
return female;
}
public void setDead(boolean dead) {
this.dead = dead;
}
public void setMale(boolean male) {
this.male = male;
}
public void setFemale(boolean female) {
this.female = female;
}
}
prints
The average time to doStuff was 0.031 ns
The average time to doStuff was 0.026 ns
The average time to doStuff was 0.000 ns
The average time to doStuff was 0.000 ns
The average time to doStuff was 0.000 ns
Thats 0.1 clock cycles on my machine, before it is optimised away completely.
How about using Set methods of EnumSet.
private static final EnumSet<Human> DEAD_MAN =
EnumSet.of(Human.MAN, Human.DEAD);
public void doStuff(EnumSet human) {
if ( human.containsAll( DEAD_MAN ) )
{
// do something
break;
}
else
{
// more common cases
}
}
Acutally EnumSet's implementation of Set interface methods is very efficient and underneath is the bitfield comparison that you are looking for.
Do the following (based on your example):
enum Human {
MAN, WOMAN, DEAD; // etc.
}
public void doStuff(Human human) {
switch (human) {
case MAN:
case DEAD:
// do something
break;
// more common cases
}
}
If you want EnumSet's then you can't use switch and should refactor it to if
public void doStuff(EnumSet<Human> human) {
if( human.containsAll(EnumSet.<Human>of(Human.MAN, Human.DEAD) {
// do something
}
}
latter variant will do bitwise comparison internally.

Enumeration help/advice - java

Is it possible to use an enumeration in the following circumstance:
Let’s say you have a certain amount of predefined 'read types'. Example read types could be: Diagnostic, KWH, MaxDemand, OnPeak, etc. And for each of these read types, there’s a ‘TIMTagNumber’ which is essientally a protocol for retrieving each predefined read type.
For example, TIMTagNumber 1100 would retrieve the read type Diagnostic
TIMTagNumber 1300 would retrieve the read type KWH.
The problem is that a predefined read type can sometimes be retrieved by more than one TIMTagNumber.
I want to create an enumeration ReadType that would define each read type and all TIMTagNumbers that can be used to retrieve that read.
Can you use an enumeration in this way?
public enum ReadType{
KWH(1300)
Diagnostic(1100)
ReadType3(1400, 1401) // This read can be retrieved by both 1400 and 1401
}
If an enumeration is not the way to go, is there an elegant or efficient way to define these read types? The overall desired outcome of all this essientally is being recognizing what type of read it is based on the TIMTagNumbers.
I.E. Given 1400 OR 1401 you would know that it's 'ReadType3'.
Can you do this? Yes. Whether it's the right decision will depend on whether you want to couple these TIMTagNumbers to the read type. If not, a simple Map<Integer, ReadType> will probably suffice.
Here's how you could do it:
public static enum MyEnum {
KWH(1300),
Diagnostic(1100),
ReadType3(1400, 1401);
private Set<Integer> timTagNumbers;
MyEnum(Integer... timTagNumbers) {
this.timTagNumbers = new HashSet<Integer>(Arrays.asList(timTagNumbers));
//add check to make sure that values are unique across all instances
}
public static MyEnum forTIMTagNumber(int num) {
for ( MyEnum readType : values() ) {
if ( readType.timTagNumbers.contains(num) ) {
return readType;
}
}
throw new NoSuchElementException("No ReadType matching TIMTagNumber " + num);
}
}
//...
int timTagNumber = 1400;
ReadType readType = ReadType.forTIMTagNumber(timTagNumber);
As I said above, this style works well when the data and the enum types are intrinsically coupled already. It would not be good for when the enum type is decoupled from the mapped values (e.g. the values are used for one of many ways of serializing the enum) or if the values are configuration-specific or even dynamic (e.g. if they were prices on an item). In these cases it is usually best to externalize this mapping in an EnumMap or Map.
public enum ReadType {
KWH(1300),
Diagnostic(1100),
ReadType3(1400, 1401);
private int[] timTagNumbers;
private ReadType(int ... numbers) {
this.timTagNumbers = numbers;
}
public int[] getTimTagNumbers() {
return timTagNumbers;
}
public static ReadType forTimTagNumber(int n) {
for (ReadType type : values()) {
if (Arrays.binarySearch(type.timTagNumbers, n) != -1) {
return type;
}
}
throw new NoSucheElementException(); // if not found
}
With this you can do
int[] timTagNumbers = ReadType.Diagnostic.getTimTagNumbers(); // [ 1100 ]
and
ReadType type3 = ReadType.forTimTagNumber(1401); // ReadType.ReadType3
You can indeed use enumerations in that way, but your example is missing a private field and a constructor.
Something like:
public enum Bla{
CASE1(100),CASE2(200);
private int amount;
private Bla(int amount) {
this.amount = amount;
}
public Bla getByValue(int value){
switch (value) {
case 100: return CASE1;
case 200: return CASE2;
}
return null;
}
}
I've included a "reverse lookup" method that returns an Enum given the value.
The main advantage is that you can have the rest of your code using "Bla" instead of int's which will guarantee type-safety on your operations, basically, it'll make impossible to pass an invalid int value as a method parameter (and you can use switch statements over enums too, and that's pretty awesome in some usage scenarios).
EDIT: I noticed after I posted that you need more then one int to specify the Enum, but the same logic applies, with the due changes in the methods, of course.
You could do something like the following, when you supply values in the parentheses where the enum variable is declared, it is calling the constructor of the enum. You need to create a different method in the enum itself to get the enum type from the integer value. See below.
public enum ReadType {
KWH(), DIAGNOSTIC(), READTYPE3();
public ReadType getReadType(int num) {
ReadType toReturn = KWH;
switch (num) {
case 1300:
toReturn = KWH;
break;
case 1100:
toReturn = DIAGNOSTIC;
break;
case 1400:
toReturn = READTYPE3;
break;
case 1401:
toReturn = READTYPE3;
break;
}
return toReturn;
}
If you can impose some restrictions like no more than 2 tags can be associated with a read type and each tag is no greater than 2^15, then you can store the two numbers into 1 integer. See this S/O post for more details.

Categories