For my project I am using enums, and I need to implement the switch-case statement, where ordinal numbers of values of the specific Enum are checked, like this way:
switch ( variable )
{
case MyEnum.A.ordinal():
return true;
case MyEnum.B.ordinal():
return true;
default:
return false;
}
Note: return values are only an example.
Unfortunately, Eclipse (I'm using 1.6 JDK) gives my compilation error "case
expressions must be constant expressions". What I should do? Is there any other method than static lookup table, described here: Convert from enum ordinal to enum type ?
This is how is done, provided you have a serialized ordinal somehow, somewhere. Usual way to persist an enum is by its name, not ordinal, though. Also you should not use ordinal in normal circumstances unless trying to implement something like EnumMap/Set. Of course, the enum can be just a port from C alike stuff and dealing with the inevitable int, needs a transform to the Enum object.
Just use Enum.values() to obtain an array ordered by ordinal(), since the array is cloned each time, keeping a ref towards is ok.
enum E{
A, B, C...
}
final static E[] vals = E.values();//copy the values(), calling values() clones the array
boolean f(int variable){
switch(vals[variable]){
case A:
...
case B:
...
//break;
default:
...
}
}
Just noticed you need only true and false, that's a Set type of behavior. You can use java.util.EnumSet or a simple long, if feeling brave (and not having more than 64 enum constants). for example:
private static <E extends Enum> long ord(E e){
return 1L<<e.ordinal();
}
static final long positiveSet = ord(E.A)+ord(E.B);
boolean f(int ordinal){
return 0!=(positiveSet&(1L<<ordinal));
}
First of all, you should not rely on the ordinal that much. If possible make your variable a String (and transform to enum using Enum.valueOf(string) or at best make it enum.
If you really can't, then use enum.values()[ordinal].Then use the enum in the switch.
The answer targets #Riaan comment on constant vs method enums and performance reasons and it doesn't directly answers the OP question, so it can be considered noise I suppose.
However, I believe it's an important matter to understand how the inner workings.
I took the benchmark off his example and improved it to remove the garbage collection and string creation that takes over 90% of the execution time. Added warm up phase to ensure hotspot actually compiles the methods.
There is some more, the benchmark is effectively callsite test. The optimization for callsites are quite different for 1, for 2 for few more and for more-more. A callsite is an invocation of abstract (or just overridden) method.
Below is the test with 6 enums constants:
package t1;
public class ZEnums {
public enum MyEnum {
A { boolean getBooleanValue(){ return true; }},
B { boolean getBooleanValue(){ return true; }},
C { boolean getBooleanValue(){ return false; }},
D { boolean getBooleanValue(){ return false; }},
E { boolean getBooleanValue(){ return false; }},
F { boolean getBooleanValue(){ return false; }},
;
abstract boolean getBooleanValue();
}
public enum MyEnumAlt {
A (true),
B (true),
C (false),
D (false),
E (false),
F (false),
;
private final boolean isTrue;
MyEnumAlt( boolean isTrue){ this.isTrue = isTrue; }
boolean getBooleanValue(){ return isTrue; };
}
public static void main(String[] args) {
log("Warming up...");
//10k iterations won't do since not all paths for MyEnum are invoked 10k (default) times to warrant compilations
long warmum = testEnum(100000 )+ testAlt(100000)+testEnum(100000 )+ testAlt(100000);
log("Warm up: %d", warmum);
//no info from +XX:+PrintCompilation below this one, or the test is invalid
testMain();
}
public static void testMain() {
int iterations = (int)4e7;
log("Testing %d iterations%n", iterations);
log("====");
log("Testing with Overridden method...");
System.gc();
{
long start = System.currentTimeMillis();
long len = 0;
len = testEnum(iterations);
long time = System.currentTimeMillis()-start;
log("Overridden method version took %dms, length: %d ", time, len);
}
////////////
System.gc();
{
log("Testing with Constant in c-tor... ");
long start = System.currentTimeMillis();
long len = testAlt(iterations);
long time = System.currentTimeMillis()-start;
log("Constant in c-tor version took %dms, length: %d ", time, len);
}
}
private static long testEnum(int iterations) {
long len = 0;
for(int i=0; i<iterations; i++){
MyEnum tmpEnum = MyEnum.A;
if(i%3==0){ tmpEnum = MyEnum.A;
}else if(i%4==0){ tmpEnum = MyEnum.B;
}else if(i%5==0){ tmpEnum = MyEnum.C;
}else if(i%6==0){ tmpEnum = MyEnum.D;
}else if(i%6==0){ tmpEnum = MyEnum.E;
}else{ tmpEnum = MyEnum.F;
}
String tmp = tmpEnum.getBooleanValue()?"XXX":"ABCDE";
len+=tmp.length();
}
return len;
}
private static long testAlt(int iterations) {
long len =0;
for(int i=0; i<iterations; i++){
MyEnumAlt tmpEnum = MyEnumAlt.A;
if(i%3==0){ tmpEnum = MyEnumAlt.A;
}else if(i%4==0){ tmpEnum = MyEnumAlt.B;
}else if(i%5==0){ tmpEnum = MyEnumAlt.C;
}else if(i%6==0){ tmpEnum = MyEnumAlt.D;
}else if(i%6==0){ tmpEnum = MyEnumAlt.E;
}else{ tmpEnum = MyEnumAlt.F;
}
String tmp = tmpEnum.getBooleanValue()?"XXX":"ABCDE";
len+=tmp.length();
}
return len;
}
static void log(String msg, Object... params){
String s = params.length>0?String.format(msg, params):msg;
System.out.printf("%tH:%<tM:%<tS.%<tL %s%n", new Long(System.currentTimeMillis()), s);
}
}
21:08:46.685 Warming up...
148 1% t1.ZEnums::testEnum # 7 (125 bytes)
150 1 t1.ZEnums$MyEnum$6::getBooleanValue (2 bytes)
152 2 t1.ZEnums$MyEnum$1::getBooleanValue (2 bytes)
154 3 t1.ZEnums$MyEnum$2::getBooleanValue (2 bytes)
155 4 t1.ZEnums$MyEnum$3::getBooleanValue (2 bytes)
158 2% t1.ZEnums::testAlt # 7 (125 bytes)
162 5 t1.ZEnums::testEnum (125 bytes)
164 6 t1.ZEnums::testAlt (125 bytes)
21:08:46.716 Warm up: 1600000
21:08:46.716 Testing 40000000 iterations
21:08:46.716 ====
21:08:46.716 Testing with Overridden method...
21:08:47.513 Overridden method version took 781ms, length: 160000000
21:08:47.513 Testing with Constant in c-tor...
21:08:48.138 Constant in c-tor version took 625ms, length: 160000000
The code was run w/ -server -XX:+PrintCompilation options.
The difference ain't huge, of course. However that's not the interesting issue. If you test the version with 2 enum constants though, the result can be significantly different. For 2 call sites the compiler generates the code by inlinining the method in question. In the test above that would remove entire the call to booleanValue and can even make execute the test in O(1).
The funniest part however is going from 2 to 3 enum constants when the compiler starts using inline caches and then the constant, and WOW magic the everything changes.
The bottom line is: proper benchmark is truly hard and involves some knowledge how the JIT compiles, when the GC might be an issue (either remove it or embrace it) and so on.
Links:
Benchmakrs on JavaOne
How NOT To Write A Microbenchmark
just use the enum constants:
MyEnum variable;
...
switch ( variable ) {
case A:
return true;
case B:
return true;
default:
return false;
}
assuming something like:
public enum MyEnum {
A, B
}
but beware of NullPointerException (if variable is null)
What you are asking for is probably:
If you need the switch in a method in the enum itself:
switch ( this )
{
case A:
return true;
case B:
return true;
default:
return false;
}
And in a different class:
switch ( variable ) //Variable of type myEnum
{
case A:
return true;
case B:
return true;
default:
return false;
}
It's easy to forget to update the switch statements if you add another enum though, so a better bet would be to put methods like this in the enum itself and use constant-specific method implementations:
public enum MyEnum
A { boolean getBooleanValue(){ return true; },
B { boolean getBooleanValue(){ return true; },
C { boolean getBooleanValue(){ return false; };
abstract boolean getBooleanValue();
}
This way, if you ever add a new enum value, the compiler will remind you to declare the getBooleanValue method and you just use A.getBooleanValue(); wherever you need it.
As was pointed out in the comments, another option is this:
public enum MyEnumAlt {
A (true),
B (true),
C (false);
private final boolean isTrue;
MyEnumAlt( boolean isTrue){ this.isTrue = isTrue; }
boolean getBooleanValue(){ return isTrue; };
}
It's a matter of preference and will vary on the specific situation. If you are simply returning a value for each enum, the constructor version is plausible, but I find it less readable. Concerns over this performing better is unfounded as you can see by testing it:
public void testMain() {
System.out.println("Testing with constructor: ");
long start = System.currentTimeMillis();
for(int i=0; i<1000*1000; i++){
MyEnum tmpEnum = null;
if(i%3==0){ tmpEnum = MyEnum.A;
}else if(i%4==0){ tmpEnum = MyEnum.B;
}else{ tmpEnum = MyEnum.C; }
String tmp = Integer.toString(i)+" "+tmpEnum.getBooleanValue();
}
long time = System.currentTimeMillis()-start;
System.out.println("Constructor version took "+time);
System.out.println("Testing with Constant specific method implementation: ");
long start2 = System.currentTimeMillis();
for(int i=0; i<1000*1000; i++){
MyEnumAlt tmpEnum2 = null;
if(i%3==0){ tmpEnum2 = MyEnumAlt.A;
}else if(i%4==0){ tmpEnum2 = MyEnumAlt.B;
}else{ tmpEnum2 = MyEnumAlt.C; }
String tmp2 = Integer.toString(i)+" "+tmpEnum2.getBooleanValue();
}
long time2 = System.currentTimeMillis()-start2;
System.out.println("Constant specific method version took "+time2);
}
A better solution would be something like this:
enum:
public interface ACServices {
public static enum MessageType {
// periodic needs to saved in DB
PIPE_INFO_TYPE_AC_DEVICE_LIST, // periodic from littlecloud
PIPE_INFO_TYPE_DEV_ONLINE,
PIPE_INFO_TYPE_DEV_OFFLINE,
PIPE_INFO_TYPE_EVENT_LOG,
PIPE_INFO_TYPE_DEV_DETAIL,
};
implementation:
ACServices.MessageType msgType = ACServices.MessageType.valueOf(acResponse.getType());
switch (msgType){
case INT_INFO_DEV_STATUS:
break;
case INT_INFO_DEV_TZ:
break;
case PIPE_INFO_DEV_COUNT:
break;
case PIPE_INFO_TYPE_AC_DEVICE_LIST:
break;
case PIPE_INFO_TYPE_CONFIG_GET_TEXT:
break;
default:
break;
}
Man Pak Hong, Dave (manpakhong#hotmail.com)
It is because the compiler sees differences. For example this enum code, we can see:
public enum TrafficLight {RED, YELLOW, GREEN}
TrafficLight trafficLights = ...
switch (trafficLights) {
case RED: {/* do stuff */}
case YELLOW: {/* do stuff */}
case GREEN: {/* do stuff */}
}
BUT the compiler see:
switch (trafficLights.ordinal()) {
case 0: {/* do stuff */}
case 1: {/* do stuff */}
case 2: {/* do stuff */}
}
That's why it throws NPE when trafficLights are NULL and you also don't know why it throws NPE in the ordinal() function even though we didn't call that method.
SOLUTION is checking NULL the ENUM before it reaches to the switch-case.
if (trafficLights != null) {
switch (trafficLights) {
case RED: {/* do stuff */}
case YELLOW: {/* do stuff */}
case GREEN: {/* do stuff */}
}
}
Related
I was unable to find a prior question like this here (which surprises me), so..
I have a working Java program where part of it analyzes typed input. Some input 'options' are the strings in the cases below.
switch (varName.toLowerCase()) {
case "steps":
common.steps = true;
break;
case "scale":
common.scale = true;
break;
case "float":
common.fracts = false;
break;
case "fraction":
common.fracts = true;
break;
case "spaces":
common.spaces = false;
break;
... etc.
}
In C or C++, I could shorten this code by making a list (which is a structure containing a string name and a variable pointer) such as
LIST varAction[] = { { "steps", &common.steps },
{ "scale", &common.scale },
.. etc.
};
and then simply checking in a loop with i = 0 thru size of the list
if ( strcmp(varAction[i].name, input) == 0) {
*varAction[i].pointer = condition;
}
The Java switch occurs more than once and is a maintenance problem, which is why I want a better way.
I could use a hashed index into an array using the hash of the string, but that would prevent me from using the specific variable names thru the code as needed, making that code less clear... i.e. I don't want to do (pseudo-code)
hashTable[varName] instead of (for example)
if ( common.fracts )
{ do something }
There must be a better way? Is there? Thanks in advance.
From your question, it's fairly clear that you know you can't do what you've said you'd do in C/C++, but just for others coming to the question: Java doesn't have references to variables.
It's tempting to push the question out a level: Look at why you have varName in the first place and see if you can avoid it.
The Java switch occurs more than once and is a maintenance problem, which is why I want a better way.
That suggests that common should have accessor function(s) for this information, so the switch exists only in one place (the getter) or two places (the getter and the setter).
void setThingy(String name, boolean value) {
switch (name.toLowerCase()) {
case "steps":
this.steps = value;
break;
case "scale":
this.scale = value;
break;
case "float":
this.fracts = value;
break;
case "fraction":
this.fracts = value;
break;
case "spaces":
this.spaces = value;
break;
// ... etc.
}
}
boolean getThingy(String name) {
switch (name.toLowerCase()) {
case "steps":
return common.steps;
case "scale":
return common.scale;
case "float":
return this.fracts;
case "fraction":
return this.fracts;
case "spaces":
return this.spaces;
// ... etc.
}
}
If common's class isn't something you can change, a static utility function somewhere would also work, but better if it's in the class if possible.
With Java 8+ you could use something like:
Map<String, Runnable> actions = new HashMap<> ();
actions.put("steps", () -> common.steps = true);
actions.put("scale", () -> common.scales = true);
//etc.
then in your code:
actions.get(varName.toLowerCase()).run(); //need null check
You could do it with Java 7- too using anonymous classes but it would be more verbose.
Here’s an option, developing my idea from the comment just a little bit. Not sure whether you will like it, I’d like to offer it in case.
public class Common {
private Map<String, Boolean> options = new HashMap<>();
public void setOption(String varName, boolean condition) {
options.put(varName.toLowerCase(), condition);
}
public boolean isSteps() { return options.get("steps"); }
public boolean isFracts() { return options.get("fractions"); }
public boolean isScale() { return options.get("scale"); }
}
You may want to put in some defense, for instance to avoid setting non-existing options.
Edit: Drawing on David Foerster’s comments on enums, here’s a solution using them:
public enum Option {
steps, scale, fraction;
private boolean option = false;
public static void setOption(String varName, boolean condition) {
valueOf(varName.toLowerCase()).option = condition;
}
public boolean isSet() {
return option;
}
}
Now the lookup happens in the setter, not in the getter. Defence against setting non-existing options is built-in: you will get an exception if you try, this behaviour can of course be modified if you prefer. The solution is quite extensible, it’s easy to add more enum constants if the need arises.
Warning: It's been a while since I last wrote some Java, and this is probably against best practices, so continue with care! Also it's just a quick and dirty example, I wrote this on a (not up to date) mobile phone...
You could try to use reflection:
class Common {
public boolean a;
public boolean b;
public boolean tryToSet(String field, boolean value) throws java.lang.Exception {
Class<?> cl = this.getClass();
try {
Field f = cl.getDeclaredField(field);
f.setBoolean(this, value);
return true;
} catch(NoSuchFieldException e) {
return false;
}
}
}
Returning a boolean gives you the possibility to implement a "default case":
if (! c.tryToSet("x", false)) {
System.out.println("some default case");
}
Try this:
import java.util.Scanner;
public class TestCases
{
static boolean steps = false;
static boolean fracts;
static boolean scale;
public static void main( String[] args )
{
Scanner input = new Scanner( System.in );
System.out.println( "Type the input" );
String typedInput = input.nextLine();
Object[][] tests = { { "steps", steps }, { "float", fracts }, { "scale", scale } };
for( int i = 0; i < tests.length; i++ )
{
if( typedInput.equals( tests[ i ][ 0 ] ) )
{
tests[ i ][ 1 ] = true;
break;
}
}
for( int i = 0; i < tests.length; i++ )
{
for( int j = 0; j < tests[ i ].length; j++ )
{
System.out.print( tests[ i ][ j ] + " " );
}
System.out.println();
}
}
}
All necessary conversions are automatically done.
So I had a previous question but realized I posted the wrong offending code. I've marked the offending statements below.
What I am trying to do is set the precedence for each of the operators with that switch statement.
Maybe someone could point me in the right direction.
Just as a note, I AM running JAVA 7 so String Switch will work.
Code
opType.java
import java.io.*;
public final class opType {
public static opType ADD = new opType( "Add" );
public static opType SUB = new opType( "Sub" );
public static opType MULT = new opType( "Mult" );
public static opType DIV = new opType( "Div" );
public static opType MOD = new opType( "Mod" );
public static opType LPAR = new opType( "LParen" );
public static opType RPAR = new opType( "RParen" );
protected String name;
private opType( String n )
{
name = n;
}
public String getName()
{
return name;
}
Operator.java
public class Operator extends Token {
protected opType val;
public boolean isOperator() { return true; }
public boolean isOperand() { return false; }
protected int getPrec()
{
switch(val.getName())
{
case "LParen":
{
return 0;
break; //unreachable
}
case "RParen":
{
return 0;
break; //unreachable
}
case "Mult":
{
return 1;
break; //unreachable
}
case "Div":
{
return 1;
break; //unreachable
}
case "Mod":
{
return 1;
break; //unreachable
}
case "Add":
{
return 2;
break; //unreachable
}
case "Sub":
{
return 2;
break; //unreachable
}
}
return 0;
}
public static int compare( Operator a, Operator b )
{
if( a.getPrec() == b.getPrec() )
return 0;
else if( a.getPrec() < b.getPrec() )
return -1;
else
return 1;
}
public opType getVal() { return val; }
public Operator( opType v ) { val = v; }
}
If you put a return, then the function returns before the break is executed and therefore the break will never be reached.
Instead you could use a variable that you set to a desired value and after the switch return that. Or just get rid of the break statements.
you already have return which will make the break unreachable
The reason that the code is unreachable is due to the return behaving like a break in that context - they both complete abruptly.
If a statement completes abruptly, then execution at that line is immediately returned to its appropriate context; if it's a break, it'll attempt to either exit the switch or return to its associated label if one exists; if it's a return, it will return to its caller, with or without a value.
This is why the code is unreachable: the line of code after the return can not be reached.
To really understand what that means or entails, we have to look at the Java Language Specification, specifically 14.1:
Every statement has a normal mode of execution in which certain
computational steps are carried out. The following sections describe
the normal mode of execution for each kind of statement.
If all the steps are carried out as described, with no indication of
abrupt completion, the statement is said to complete normally.
However, certain events may prevent a statement from completing
normally:
The break (§14.15), continue (§14.16), and return (§14.17) statements
cause a transfer of control that may prevent normal completion of
statements that contain them.
Evaluation of certain expressions may throw exceptions from the Java
Virtual Machine (§15.6). An explicit throw (§14.18) statement also
results in an exception. An exception causes a transfer of control
that may prevent normal completion of statements.
If such an event occurs, then execution of one or more statements may
be terminated before all steps of their normal mode of execution have
completed; such statements are said to complete abruptly.
An abrupt completion always has an associated reason, which is one of
the following:
A break with no label
A break with a given label
A continue with no label
A continue with a given label
A return with no value
A return with a given value
A throw with a given value, including exceptions thrown by the Java
Virtual Machine
The terms "complete normally" and "complete abruptly" also apply to
the evaluation of expressions (§15.6). The only reason an expression
can complete abruptly is that an exception is thrown, because of
either a throw with a given value (§14.18) or a run-time exception or
error (§11, §15.6).
If a statement evaluates an expression, abrupt completion of the
expression always causes the immediate abrupt completion of the
statement, with the same reason. All succeeding steps in the normal
mode of execution are not performed.
Unless otherwise specified in this chapter, abrupt completion of a
substatement causes the immediate abrupt completion of the statement
itself, with the same reason, and all succeeding steps in the normal
mode of execution of the statement are not performed.
Unless otherwise specified, a statement completes normally if all
expressions it evaluates and all substatements it executes complete
normally.
The return statement effectively exits the method immediately. Since you've placed return statements inside the switch block for each case, whichever case is matched will, according to your code, return whatever value is indicated immediately. The break therefore cannot be executed, hence the error. You have two options:
1- Set a value, and return at the end of the method:
protected int getPrec(){
int prec = 0;
switch(val.getName()) {
case "LParen":
prec = 0;
break;
case "RParen":
prec = 0;
break;
case "Mult":
prec = 1;
break;
case "Div":
prec = 1;
break;
case "Mod":
prec = 1;
break;
case "Add":
prec = 2;
break;
case "Sub":
prec = 2;
break;
default:
prec = 0;
break; // technically unnecessary since we're at the end already but adding for completeness.
}
return prec;
}
2- Ditch the break; statements and keep the return statements as you've written them.
Personally I would prefer the first option as its cleaner and more readable to me. Plus it makes it easier to expand whatever actions need to be done in one or more cases if need be in the future.
By the way, watch your naming convention. You presently have:
public final class opType // bad naming
Since this is a class, the Java standard is to capitalize the first letter of the class. So it should be:
public final class OpType // good naming
Here you can comment the line return super.onOptionsItemSelected(item)
after commenting this line the code will run.
This Works for me
public boolean onOptionsItemSelected(MenuItem item) {
//return super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.aboutUS:
Intent i = new Intent("com.code.myapp.ABOUT");
startActivity(i);
break;
case R.id.preferences:
break;
}
return false;
}
I'm trying to figure out if there is something wrong with the way I'm creating Object arrays in my code, or if handling Object arrays in Java is more expensive than I originally thought it was.
I have a simple enum class called ElementaryTransitionTerm, consisting of ony two primitive member variables. A method in another class creates an array consisting of a combination of this Enum's constants (with the possible length of the array never exceeding 3).
The problem is that in total, the program spends (on average) 13ms inside said method, though it is called only 8 times. I have no idea why.
Running times were calculated 2 ways:
Surrounding the call to the method by System.nanoTime() calls.
Surrounding each array creation statement inside the method by
System.nanoTime() calls and summing them up
Here is the ElementaryTransitionTerm enum class:
public enum ElementaryTransitionTerm
{
MATCH(1, 0), INSERTION(0, 1), SUBSTITUTION(1, 1), DELETION(0, 0), FAILURE(0, 0);
private final int I_OFFSET;
private final int E_OFFSET;
private ElementaryTransitionTerm(int iOffset, int eOffset)
{
I_OFFSET = iOffset;
E_OFFSET = eOffset;
}
}
Here is the method in question, createTransitionTerms (as well as the declaration of the enum type used as a parameter):
//'E' and 'I' are both private int fields in the parent class.
private enum RelevantSubwordHitIndexType { FIRST_INDEX, TRAILING_INDEX, NO_INDEX };
/**
* Creates an array of ElementaryTransitionTerm constants.
* #param hitIndexType a RelevantSubwordHitIndexType enum constant
*/
private ElementaryTransitionTerm[] createTransitionTerms(RelevantSubwordHitIndexType hitIndexType)
{
//Simple getter method chained in to String.length() call
int onePastFinalBoundary = parentAutomaton.getAutomatonString().length();
if(E < parentAutomaton.getMaxEditDistance()) //Simple getter method retrieving an int
{
if(I < onePastFinalBoundary - 1)
{
switch(hitIndexType)
{
case FIRST_INDEX: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.MATCH};
case TRAILING_INDEX: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.INSERTION, ElementaryTransitionTerm.SUBSTITUTION, ElementaryTransitionTerm.DELETION};
default: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.INSERTION, ElementaryTransitionTerm.SUBSTITUTION};
}
}
else if(I == onePastFinalBoundary - 1)
{
switch(hitIndexType)
{
case FIRST_INDEX: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.MATCH};
default: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.INSERTION, ElementaryTransitionTerm.SUBSTITUTION};
}
}
else return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.INSERTION};
else
{
if(I < onePastFinalBoundary)
{
switch(hitIndexType)
{
case FIRST_INDEX: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.MATCH};
default: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.FAILURE};
}
}
else return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.FAILURE};
}
}
The method essentially evaluates a small set of conditionals in order to create a small array. However, the total execution time of 8 runs of this method does not reflect that.
I've even gone so far as to declare the to-be-returned arrays as public final arrays in ElementaryTransitionTerm, and replace the creation statements in the above methods with references to these arrays, but it has absolutely no effect on the code's running time.
I've written code that does more in less time. So I'm curious as to why this method is behaving like this. Does anyone have any ideas?
EDIT:
After further testing, i've discovered a two things:
Testing the method in isolation yields expected (i.e
sub-millisecond) results.
Testing the method within the program, it seems as though whichever
array creation statement is executed on the first call to the
function is essentially responsible for the times i'm seeing. All
subsequent calls complete in sub-millisecond times.
Concerning #2: What is the reason for this, and how can I go about rectifying it?
Ran your code, I get 25-30 ms time for one million calls to that method. Running ona Sony Vaio Z, i5, 4 GB Ram, Win 7 64 but, JDK 6 64 bit.
Here's the actual code I tried:
private ElementaryTransitionTerm[] createTransitionTerms(RelevantSubwordHitIndexType hitIndexType) {
//Simple getter method chained in to String.length() call
int onePastFinalBoundary = "A".length();
//Here I also tried if(1 < 2) to change the if/else execution path, same run time for each.
if(3 < 2) {
if(1 < 2) {
switch(hitIndexType) {
case FIRST_INDEX: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.MATCH};
case TRAILING_INDEX: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.INSERTION, ElementaryTransitionTerm.SUBSTITUTION, ElementaryTransitionTerm.DELETION};
default: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.INSERTION, ElementaryTransitionTerm.SUBSTITUTION};
}
} else if(1 == 1) {
switch(hitIndexType) {
case FIRST_INDEX: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.MATCH};
default: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.INSERTION, ElementaryTransitionTerm.SUBSTITUTION};
}
}
else {
return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.INSERTION};
}
} else {
if(1 < 2) {
switch(hitIndexType) {
case FIRST_INDEX: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.MATCH};
default: return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.FAILURE};
}
} else {
return new ElementaryTransitionTerm[] {ElementaryTransitionTerm.FAILURE};
}
}
}
public static void main(String args[]) {
T1 t = new T1();
long st = System.currentTimeMillis();
for(int i = 0 ; i<1000000; i++) {
t.createTransitionTerms(RelevantSubwordHitIndexType.FIRST_INDEX);
}
long et = System.currentTimeMillis();
System.out.println(et-st);
}
Can you tell us on what Hardware, OS, JDK version were you testing?
To complete Shivan's answer, I have run a test with randomly generated input (one million time) and I get results between 40 and 50ms.
Here is the the random generation part :
public MyTest() {
Random r = new Random();
parentAutomaton = new ParentAutomaton();
parentAutomaton.maxEditDistance = r.nextInt(255);
parentAutomaton.automatonStringLen = r.nextInt(255);
E = r.nextInt(255);
I = r.nextInt(255);
relevantSubwordHitIndexType = RelevantSubwordHitIndexType.values()[r.nextInt(3)];
}
and the execution method :
public static void main(String [] args) {
List<MyTest> l = new ArrayList<MyTest>();
for (int i = 0; i < 1000000; i++) {
l.add(new MyTest());
}
long start = System.nanoTime();
for (MyTest t:l) {
t.createTransitionTerms(t.relevantSubwordHitIndexType);
}
double dur_nano = System.nanoTime() - start;
double dur_mili = dur_nano / 1000000.0;
System.out.println("Finished in : " + dur_mili);
}
My OS is Ubuntu 12.04 and my CPU is an Intel(R) Core(TM)2 Duo CPU T7250 # 2.00GHz with 2GB ram. I ran it with Java 1.6.0_24.
Let me know if you want the full source code.
Hope it helps,
It might be worth an experiment to try the following ideas:
Pre-create some of the arrays such as return new ElementaryTransitionTerm[] { ElementaryTransitionTerm.INSERTION }; and keep them as private static values.
Reorder your cases and conditions so if there is one branch that is much more commonly executed than the others, then put that first somehow.
I have the below piece of code that I have developed ..
public byte determineCardType(final IInput inputData) {
byte cardType = UNKNOWN_CARD;
try {
if (isWagRewardsLoyaltyCard(inputData))
cardType = WAG_LOYALTY_CARD_TYPE;
else if (isDRCard(inputData)) //checking that card scanned and swiped is a DR Card
cardType = DR_CARD_TYPE;
else if (isWagRewardsPartnerCard(inputData))
cardType = AARP_CARD_TYPE;
return cardType;
} catch (Exception e) {
return UNKNOWN_CARD;
}
}
please advise me can the above code can be adjusted in switch loop, if yes then please advise, Thanks in advance.
the other code that is linked to it...
if((aarpCardSupport.isAARPCard(input))||(determineCardType(input)==DR_CARD_TYPE)) {
return true;
} else if((isDRCard(input))&&(isDRLoayltyEnabled())) { //would return 1 for DR card only when isDRLoayltyEnabled returns true
return true;
}
return false ;
Switch won't help you, but conditional expressions can:
return isWagRewardsLoyaltyCard(inputData) ? WAG_LOYALTY_CARD_TYPE
: isDRCard(inputData) ? DR_CARD_TYPE
: isWagRewardsPartnerCard(inputData) ? AARP_CARD_TYPE
: UNKNOWN_CARD;
I would strongly recommend against catching Exception, btw. Catch specific exception types if you must - although in that case I'd at least log the error before returning.
EDIT: As for the second piece of code, it looks like you just want:
return aarpCardSupport.isAARPCard(input)
|| determineCardType(input) == DR_CARD_TYPE
|| (isDRCard(input) && isDRLoayltyEnabled);
Although why determineCardType(input) would return something other than DR_CARD_TYPE when isDRCard(input) returns true is a mystery...
Don't do it. If you must do it, you could do it like this:
public byte determineCardType (final IInput inputData) {
byte cardType = UNKNOWN_CARD;
try {
switch (isWagRewardsLoyaltyCard (inputData) ? 1 :
(isDRCard (inputData) ? 2 : (isWagRewardsPartnerCard (inputData) ? 3 : 4)))
{
case 1: cardType = WAG_LOYALTY_CARD_TYPE; break;
case 2: cardType = DR_CARD_TYPE; break;
case 3: cardType = AARP_CARD_TYPE; break;
default: // UNKNOWN_CARD already default
}
return cardType;
} catch (CardException ce) {
return UNKNOWN_CARD;
}
}
}
But since you return a cardType as byte, you can switch later, after setting the type. This code is harder to read than your code. Jons code is at least lean.
I see you're new to switch statements. So I elaborate a little.
A switch statement is useful if your input is in Integral form (int, byte, short, Enum), and if you can match it against a - mostly medium short list of values.
And if you otherwise would use a sequence of if/else statements. Case statements needn't be mutual exclusive, but most times they are.
In your case, you call 3 methods which return booleans, so the input isn't integral. But your output is.
Later in the code, you could write:
byte cardType = determineCardType (inputDate);
switch (cardType)
{
case WAG_LOYALTY_CARD_TYPE: doWlct (foo, bar); break;
case DR_CARD_TYPE: doDct (); break;
case AARP_CARD_TYPE: doAct (baz); foobar (); break;
case UNKNOWN_CARD: System.err.println ("Unknown card");
}
Else you would have to write:
if (cardType == WAG_LOYALTY_CARD_TYPE)
doWlct (foo, bar);
else if (cardType == DR_CARD_TYPE)
doDct ();
else if (cardType == AARP_CARD_TYPE) {
doAct (baz);
foobar ();
}
else ...
Since Java 1.7 switch over Strings is possible as well, but until then, you could only switch over integral types, and the case labels have to be literally constant and known at compile time.
In OOP, switch statements are often abandoned in favor of dynamic dispatch.
interface Card {
public abstract int authenticate ();
}
class WagLoyalityCard implements Card {
public int authenticate () {
doWlct (foo, bar);
}
}
class DrCard implements Card {
public int authenticate () {
doDct ();
}
}
// ... and so on
Card card = new DrCard ();
// authenticate:
card.authenticate ();
// depending on the card type, DrCard.authenticate () or
// WagCard.authenticate () gets called.
I need to change the following if's to a switch-case while checking for a String, to improve the cyclomatic complexity.
String value = some methodx;
if ("apple".equals(value)) {
method1;
}
if ("carrot".equals(value)) {
method2;
}
if ("mango".equals(value)) {
method3;
}
if ("orange".equals(value)) {
method4;
}
But I am not sure what value I'm going to get.
Java (before version 7) does not support String in switch/case. But you can achieve the desired result by using an enum.
private enum Fruit {
apple, carrot, mango, orange;
}
String value; // assume input
Fruit fruit = Fruit.valueOf(value); // surround with try/catch
switch(fruit) {
case apple:
method1;
break;
case carrot:
method2;
break;
// etc...
}
Everybody is using at least Java 7 now, right? Here is the answer to the original problem:
String myString = getFruitString();
switch (myString) {
case "apple":
method1();
break;
case "carrot":
method2();
break;
case "mango":
method3();
break;
case "orange":
method4();
break;
}
Notes
The case statements are equivalent to using String.equals.
As usual, String matching is case sensitive.
According to the docs, this is generally faster than using chained if-else statements (as in cHao's answer).
Learn to use else.
Since value will never be equal to two unequal strings at once, there are only 5 possible outcomes -- one for each value you care about, plus one for "none of the above". But because your code doesn't eliminate the tests that can't pass, it has 16 "possible" paths (2 ^ the number of tests), of which most will never be followed.
With else, the only paths that exist are the 5 that can actually happen.
String value = some methodx;
if ("apple".equals(value )) {
method1;
}
else if ("carrot".equals(value )) {
method2;
}
else if ("mango".equals(value )) {
method3;
}
else if ("orance".equals(value )) {
method4;
}
Or start using JDK 7, which includes the ability to use strings in a switch statement. Course, Java will just compile the switch into an if/else like construct anyway...
To reduce cyclomatic complexity use a map:
Map<String,Callable<Object>> map = new HashMap < > ( ) ;
map . put ( "apple" , new Callable<Object> () { public Object call ( method1 ( ) ; return null ; } ) ;
...
map . get ( x ) . call ( ) ;
or polymorphism
Just to make concrete emory's answer, the executable code is the following :
Map<String,Callable<USer>> map = new HashMap<String,Callable<User>>();
map.put( "test" , new Callable<User> () { public User call (){ return fillUser("test" ); }} ) ;
map.put( "admin" , new Callable<Utente> () { public Utente call (){ return fillUser("admin" ); }} ) ;
where user is a POJO, and then
User user = map.get(USERNAME).call();
finally the called method is somewhere :
private User fillUser(String x){
User user = new User();
// set something in User
return user;
}
Java does not support Switch-case with String. I guess this link can help you. :)
Here is a possible pre-1.7 way, which I can't recommend:
public class PoorSwitch
{
final static public int poorHash (String s) {
long l = 0L;
for (char c: s.toCharArray ()) {
l = 97*l + c;
}
return (int) l;
}
public static void main (String args[])
{
String param = "foo";
if (args.length == 1)
{
param = args[0];
}
// uncomment these lines, to evaluate your hash
// test ("foo");
// test ("bar");
switch (poorHash (param)) {
// this doesn't work, since you need a literal constant
// so we have to evaluate our hash beforehand:
// case poorHash ("foo"): {
case 970596: {
System.out.println ("Foo!");
break;
}
// case poorHash ("bar"): {
case 931605: {
System.out.println ("Bar!");
break;
}
default: {
System.out.println ("unknown\t" + param);
break;
}
}
}
public static void test (String s)
{
System.out.println ("Hash:\t " + s + " =\t" + poorHash (s));
}
}
Maybe you could work with such a trick in a generated code. Else I can't recommend it. Not so much that the possibility of a hash collision makes me worry, but if something is mixed up (cut and paste), it is hard to find the error. 931605 is not a good documentation.
Take it just as proof of concept, as curiosity.
We can apply Switch just on data type compatible int :short,Shor,byte,Byte,int,Integer,char,Character or enum type.
Evaluating String variables with a switch statement have been implemented in Java SE 7, and hence it only works in java 7. You can also have a look at how this new feature is implemented in JDK 7.
Java 8 supports string switchcase.
String type = "apple";
switch(type){
case "apple":
//statements
break;
default:
//statements
break; }
String name,lname;
name= JOptionPane.showInputDialog(null,"Enter your name");
lname= JOptionPane.showInputDialog(null,"Enter your father name");
if(name.equals("Ahmad")){
JOptionPane.showMessageDialog(null,"welcome "+name);
}
if(lname.equals("Khan"))
JOptionPane.showMessageDialog(null,"Name : "+name +"\nLast name :"+lname );
else {
JOptionPane.showMessageDialog(null,"try again " );
}
}}
Not very pretty but here is another way:
String runFct =
queryType.equals("eq") ? "method1":
queryType.equals("L_L")? "method2":
queryType.equals("L_R")? "method3":
queryType.equals("L_LR")? "method4":
"method5";
Method m = this.getClass().getMethod(runFct);
m.invoke(this);
String value = someMethod();
switch(0) {
default:
if ("apple".equals(value)) {
method1();
break;
}
if ("carrot".equals(value)) {
method2();
break;
}
if ("mango".equals(value)) {
method3();
break;
}
if ("orance".equals(value)) {
method4();
break;
}
}