Using reserved words in an enum / switch statement, best workaround? - java

I am writing a flat file parser that reads token/value pairs using a Scanner. The files being read contain the token "class". The token is later used in a switch statement, and uses the (pre Java 7) valueOf(token) Java idiom to produce an enum value. (I am using Java6 for compatibility with GWT.) As a workaround, I am using uppercase values in the enum, and valueOf(token.toUpperCase()).
public enum ParseTags {
CODE, CLASS, INSTRUCTOR, HOURS;
}
// . . .
token = scanner.next();
value = scanner.next();
switch (ParseTags.valueOf(token.toUpperCase())) {
case CODE:
entry.setCode(value);
break;
case CLASS:
entry.setClass(value);
break;
Because this is being compiled into javascript, I want to avoid the extra "toUpperCase()" operation on each iteration; not sure what performance will be on target platform. Is there a more graceful way to represent reserved words in an enumeration? This would be handled well by Java7's switch on String, but again, I am confined to Java6sdk.

What you're doing right now is the preferred way to do it. I would be extraordinarily shocked if the toUpperCase were a bottleneck.
That said, I might consider something like
enum ParseTags {
CODE {
public void set(Entry entry, String value) {
entry.setCode(value);
}
},
...;
public abstract void set(Entry entry, String value);
}
so you can do
ParseTags.valueOf(token.toUpperCase()).set(entry, value);

Related

Java enum giving incorrect values [duplicate]

This question already has answers here:
Is custom enum Serializable too?
(3 answers)
Closed 2 years ago.
I have recently started to use Java after a long period of using C,C++ and C#. I can't get my head around how Java enums are supposed to work.
After some research I have created the following:
public class RedRoad implements Serializable, Parcelable
{
// ... other parts removed for clarity
public enum State
{
NOT_STARTED(0),
PART_DONE(1),
COMPLETED(2);
private int value;
private State(int value) {
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
}
I am storing these State values in an sqlite database as ints using getValue(), retrieving them using setValue(), then sending the resulting ''Road' objects via a broadcast. Then I am doing this:
switch (road.state) {
case COMPLETED:
pline.getOutlinePaint().setColor(Color.GREEN); break;
case PART_DONE:
pline.getOutlinePaint().setColor(Color.argb(0xFF,0xFF,0xA5,0x00)); break;
case NOT_STARTED:
default: pline.getOutlinePaint().setColor(Color.RED);
}
but the first two cases are never called, even though I have checked that road.state.getValue() is sometimes 1 , not zero.
Furthermore, if I change the switch code to this:
switch (road.state.getValue()) {
case 2:
pline.getOutlinePaint().setColor(Color.GREEN); break;
case 1:
Log.d("*** road state ", String.valueOf(road.state.getValue()));
Log.e("*** road state ", String.valueOf(road.state));
pline.getOutlinePaint().setColor(Color.argb(0xFF,0xFF,0xA5,0x00));
break;
case 0:
default:
pline.getOutlinePaint().setColor(Color.RED);
}
then the colour gets set as requested. And I get an extraordinary ouput in the log:
D/*** road state: 1
E/*** road state: NOT_STARTED
How can this be? NOT_STARTED is defined as zero!
[Edit]
Later discovered that , apart from the above, (which I can find a workaround for), the values are incorrect after being sent from the async task to the main activity (the 'Road' class is parcelable). If I log state.getValue() before sending , then again after receipt, any non-zero values have changed to zero.
You're calling String.valueOf on an enum constant in the second instance, which calls the toString method of the enum. The default toString implementation of enums returns the name field, which makes NOT_STARTED the valid return value.
Enums are essentially abstract classes with a finite number of implementations, with each implementation guaranteed to only exist once per JVM.
#AndyTurner is correct about not using a setter. I have now done some more tests, in a new app specially created, and the setter gives totally unpredictable results.
So the solution I have used (for setting the value from an 'int' in the db) is a somewhat boring
protected void setState(int i) {
switch (i)
{
case 2: state = State.COMPLETED; break;
case 1: state = State.PART_DONE; break;
default: state = State.NOT_STARTED;
}
}
Although this works , it seems to me to partly defeat the reason for using an Enum (instead of an int) to start with.
And, since creating the setter (that I had originally) gives incorrect results, I wonder why Android Studio (4.1) didn't give me a warning about it? It's very happy to give me warnings about so many other (less important) things.

java enum string matching

I have an enum as follows:
public enum ServerTask {
HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
}
I also have a string (lets say string = "Execute") which I would like to make into an instance of the ServerTask enum based on which string in the enum that it matches with. Is there a better way to do this than doing equality checks between the string I want to match and every item in the enum? seems like this would be a lot of if statements since my enum is fairly large
At some level you're going to have to iterate over the entire set of enumerations that you have, and you'll have to compare them to equal - either via a mapping structure (initial population) or through a rudimentary loop.
It's fairly easy to accomplish with a rudimentary loop, so I don't see any reason why you wouldn't want to go this route. The code snippet below assumes the field is named friendlyTask.
public static ServerTask forTaskName(String friendlyTask) {
for (ServerTask serverTask : ServerTask.values()) {
if(serverTask.friendlyTask.equals(friendlyTask)) {
return serverTask;
}
}
return null;
}
The caveat to this approach is that the data won't be stored internally, and depending on how many enums you actually have and how many times you want to invoke this method, it would perform slightly worse than initializing with a map.
However, this approach is the most straightforward. If you find yourself in a position where you have several hundred enums (even more than 20 is a smell to me), consider what it is those enumerations represent and what one should do to break it out a bit more.
Create static reverse lookup map.
public enum ServerTask {
HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
FINAL_ITEM("Final item");
// For static data always prefer to use Guava's Immutable library
// http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html
static ImmutableMap< String, ServerTask > REVERSE_MAP;
static
{
ImmutableMap.Builder< String, ServerTask > reverseMapBuilder =
ImmutableMap.builder( );
// Build the reverse map by iterating all the values of your enum
for ( ServerTask cur : values() )
{
reverseMapBuilder.put( cur.taskName, cur );
}
REVERSE_MAP = reverseMapBuilder.build( );
}
// Now is the lookup method
public static ServerTask fromTaskName( String friendlyName )
{
// Will return ENUM if friendlyName matches what you stored
// with enum
return REVERSE_MAP.get( friendlyName );
}
}
If you have to get the enum from the String often, then creating a reverse map like Alexander suggests might be worth it.
If you only have to do it once or twice, looping over the values with a single if statement might be your best bet (like Nizil's comment insinuates)
for (ServerTask task : ServerTask.values())
{
//Check here if strings match
}
However there is a way to not iterate over the values at all. If you can ensure that the name of the enum instance and its String value are identical, then you can use:
ServerTask.valueOf("EXECUTE")
which will give you ServerTask.EXECUTE.
Refer this answer for more info.
Having said that, I would not recommend this approach unless you're OK with having instances have the same String representations as their identifiers and yours is a performance critical application which is most often not the case.
You could write a method like this:
static ServerTask getServerTask(String name)
{
switch(name)
{
case "Execute": return HOOK_BEFORE_ALL_TASKS;
case "Copy master db": return COPY_MASTER_AND_SNAPSHOT_TO_HISTORY;
case "Process Check-In Queue": return PROCESS_CHECKIN_QUEUE;
}
}
It's smaller, but not automatic like #Alexander_Pogrebnyak's solution. If the enum changes, you would have to update the switch.

How to check Type Ranges with Java development tools (JDT)?

I want to parse a String, which contains a number, using JDT to find out whether the contained number is inside the valid Range of one of the Primitive Types.
Let's say i got a float value like this as String "1.7976931348623157e350" and want to see whether it is still inside the allowed range for primitive type 'double'. (In this case it would not be inside the valid range, because the maximum exponent of double is 308).
I don't want to use the standard methods like : Double.parseDouble("1.7976931348623157e350"), because I'm afraid it might be too slow if I have a big amount of primitive types, which I want to check .
If you know the Eclipse development environment you will know that inside a normal java file, eclipse is able to tell whether a variable is out of range or not, by underlining it red, in the the case of 'out of range'. So basically i want to use this functionality. But as you can guess - it's easier said then done!
I have started experimenting with the ASTParser from this library: org.eclipse.jdt.core.dom
But I must admit I was not very successful here.
First i tried calling some of those vistor methods using methods like:
resolveBinding() , but they always only returned me "Null".
I have found some interesting class called ASTSyntaxErrorPropagator , but i'm not sure how this is used correctly. It seems to propagate parsing problems or something like that and gets it's information delivered by some thing class called CodeSnippetParsingUtil I assume. Anyways, these are only speculations.
Does anyone know how to use this ASTParser correctly?
I would be really thankful for some advice.
Here is some basic code-snipped which I tried to debug:
public class DatatypesParser {
public static void main(String[] args) {
ASTParser parser = ASTParser.newParser(AST.JLS4);
Map options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
String statement = new String("int i = " + Long.MAX_VALUE + ";");
parser.setSource(statement.toCharArray());
parser.setKind(ASTParser.K_STATEMENTS);
parser.setResolveBindings(true);
parser.setBindingsRecovery(true);
ASTNode ast = parser.createAST(null);
ast.accept(new ASTVisitor() {
#Override
public boolean visit(VariableDeclarationStatement node) {
CodeSnippetParsingUtil util = new CodeSnippetParsingUtil();
return true;
}
});
}
I don't want to use the standard methods like :
Double.parseDouble("1.7976931348623157e350"), because i'm afraid it
might be too slow if i have a big amount of primitive types, which i
want to check .
Under the hood JDT is actually using the standard methods of Double to parse the value, and quite a bit more - so you should always use the standard methods if performance is a concern.
Here is how the double gets parsed by JDT.
From org.eclipse.jdt.internal.compiler.ast.DoubleLiteral:
public void computeConstant() {
Double computedValue;
[...]
try {
computedValue = Double.valueOf(String.valueOf(this.source));
} catch (NumberFormatException e) {
[...]
return;
}
final double doubleValue = computedValue.doubleValue();
if (doubleValue > Double.MAX_VALUE) {
// error: the number is too large to represent
return;
}
[...]
}

How to convert NFA/DFA to java?

I have a scenario where I have designed the NFA and using JFLAP I have converted it to DFA.
I need to know, how to code it in Java?
Basically how to implement those state transitions in Java. I have seen some examples which do this using switch and if statements, but I can't see any relation to DFA/NFA design and how to use it to implement in Java.
if you want to use a more object oriented design over while(true)switch(state){...}
public class State{
private Map<Character,State> transitions=new HashMap<Character,State>();
public void addTransition(char ch,State st){
transitions.put(ch,st);
}
public State next(char ch){
return transitions.get(ch);
}
private boolean fin=false;
public boolean isFinal(){return fin;}
public boolean setFinal(boolean f){fin=f;}
}
and then the loop will be
State currState=startState;
while(currState!=null && input.hasNextChar()){//you can also end directly when final state is reached
char next = input.nextChar();//get next character
currState = currState.next(next);
}
if(currState!=null && currState.isFinal()){
// reached final state
}else{
// to bad didn't match
}
Take a look at dk.brics.automaton:
This Java package contains a DFA/NFA (finite-state automata) implementation with Unicode alphabet (UTF16) and support for the standard regular expression operations (concatenation, union, Kleene star) and a number of non-standard ones (intersection, complement, etc.)
Although you would have implemented it by now but there is very good implementation which is easy to digest. Use Digraph to maintain the epsilon transitions and stack to keep track of expressions. Check out this link from RS NFA.java .

what is Java best practice to handle enum's

hi I know Java for a long time and recently I have been diving deep to the Java world.
As an experienced c# developer I find it odd to use Java enum's.
For example if I show on console items such as :
public enum AdminOpertionFirstlayer
{MANAGE_SUPPLY,
MANAGE_CUSTOMERS_SERVICE,
ORDERS_MANAGEMENT,
REPORTING_OPRATIONES}
I find it hard to write them down to the user , cause I have to define new varible
*AdminOpertionFirstlayer []adminOpertionFirstlayerArr =
AdminOpertionFirstlayer.values();
in order to achieve this :
for (int i = 0; i < adminOpertionFirstlayerArr.length; i++) {
String s = String.format("%d. %s",
i+1,
adminOpertionFirstlayerArr[i].toString());
Screen.print(s);
}
AdminOpertionFirstlayer chosen= adminOpertionFirstlayerArr
[(Integer.parseInt(dataIn.readLine()))-1];
But I feel it's a bad practice to declare on *
Is there a best practice (enum extension is one ... ) ?
Is there TryParse available or every time I parse I should try and catch ?
thank you
EDIT
does doing this is understandable and readable ?
public enum MainMenuOptiones{
ADMIN {public void secondLayerMenu(){
Main.AdminSecondLayerMenu();}},
CUSTOMER{public void secondLayerMenu(){
Main.customerSecondLayerMenu();}},
EXIT{public void secondLayerMenu(){
System.exit(1);}},
UNAPPLICABLE{public void secondLayerMenu(){
Screen.printToScreen("chice doesnt exist try again");}};
abstract public void secondLayerMenu();
}
the phrphes is instead of using all the switch mechanism
I can use
enumInstance.secondLayerMenu();
You could use Java's enhanced for loop (and the ordinal value for the enum)
for (AdminOperatorFirstLayer operator : AdminOperatorFirstLayer.values()) {
String s = String.format("%d. %s", operator.ordinal(), operator);
Screen.print(s);
}
Then you can use the ordinal value to recreate the enum:
AdminOperatorFirstLayer chosen =
AdminOperatorFirstLayer.values()[(Integer.parseInt(dataIn.readLine()))];
Or you could use the name:
for (AdminOperatorFirstLayer operator : AdminOperatorFirstLayer.values()) {
String s = String.format("%s. %s", operator.name(), operator);
Screen.print(s);
}
Then you can use valueOf value to recreate the enum:
AdminOperatorFirstLayer chosen =
AdminOperatorFirstLayer.valueOf(dataIn.readLine()];
The Enum<E> class is the base for all enums in Java.
There's no need to declare a variable with values, use an enhanced for loop to print them out if you want the users to read your source code.
Generally you want to print out a localised string rather than the name of the enum in the source.
There isn't an equivalent to TryParse, instead use AdminOpertionFirstlayer.valueOf(AdminOpertionFirstlayer.class, string) and catch the IllegalArgumentException.

Categories