So, I know you can't use a variable in the case statement. I am hoping someone can point me to code that would be fairly efficient as a replacement. (I could do a bunch of ifs, for example).
The situation is that I have an array of object data, and I want to iterate through that array. The position in the array is given by a name as shown below (the int...ordinal statements). Basically I have to assign generate 'result' objects for certain members of the array (if they are discrete data such as C_VENT_RATE). The only way I can see this done easily is do a bunch of ifs such as if (i.equals(pr_int)).
ArrayList<String[]> rawEKGs = ekgFile.getForMrno( docInfo.getMedicalRecordNumber() );
for (String[] parts : rawEKGs) {
for (int i=0; i< parts.length; i++ )
{
Result result = docInfo.getResult();
boolean process = true;
final int vent_rate = UncEKG.COL_NAMES.C_VENT_RATE.ordinal();
int art_rate = UncEKG.COL_NAMES.C_ART_RATE.ordinal();
int pr_int = UncEKG.COL_NAMES.C_PR_INTERVAL.ordinal();
int qrs_dur = UncEKG.COL_NAMES.C_QRS_DURATION.ordinal();
int qt_qtc = UncEKG.COL_NAMES.C_QT_QTC.ordinal();
int prt = UncEKG.COL_NAMES.C_PRT_AXES.ordinal();
switch(i) {
case : // something
break;
default: process = false;
}
Since you already have an enum, you can try the Command pattern using an EnumMap mapping your enum to a Command.
Each Command instance will be the same logic as one of your case statements.
EnumMap<UncEKG.COL_NAMES, Command> map = ...
//values is in ordinal order
//pulled out for performance reasons
UncEKG.COL_NAMES[] names = UncEKG.COL_NAMES.values();
for (String[] parts : rawEKGs) {
for (int i=0; i< parts.length; i++ ){
map.get(names[i]).execute();
}
}
I think the right way is to put the logic in the enum. So you would add a static method to the enum class to get the right column based on the int, and then you can switch based on the enum, or perhaps do something else, or even better have a method on the enum which says if that column is processed or not (although that may not be appropriate if the enum is more general purpose).
Quick and dirty would look like this, though:
ArrayList<String[]> rawEKGs = ekgFile.getForMrno( docInfo.getMedicalRecordNumber() );
UncEKG.COL_NAMES[] values = UncEKG.COL_NAMES.values();
for (String[] parts : rawEKGs) {
for (int i=0; i< parts.length; i++ )
{
Result result = docInfo.getResult();
boolean process = true;
switch (values[i]) {
case UncEKG.COL_NAMES.C_VENT_RATE:
break;
default: process = false;
}
}
}
Do like this way
switch(i) {
case 0: // something
break;
case 1: // something
break;
case 2: // something
break;
.
.
.
.
default: process = false;
}
If the object contains an enum (UncEKG) as a variable, why not just use the switch on the enum
switch (theEnum) {
case UncEKG.COL_NAMES.C_VENT_RATE:
//something
break;
case UncEKG.COL_NAMES.C_PR_INTERVAL:
//something else
break;
default: process = false
}
Enum info
Related
I am using a random number in a switch case. So have something like:
public void something {
Random myRand = new Random();
int number = myRand.nextInt(10 - 1) + 1;
switch(number)
case 1:
Do something and on completion go back and start running the something method again.
break:
case 1;
Do something and on completion go back and start running the something method again.
break;
Each case statement could be run through any number of times depending on input from user, some may not even be used.
What I would like is something inside the case statement saying :-
public void something (run);
Is what I am trying to do possible or is there a better way?
You can use do-while statement in this case with a condition to stop the execution.
Call your something method inside do while.
do {
something();
} while(condition);
This will call your method execute your switch case and again call your something method.
may i suggest you using interfaces?
what you are trying to implement is known as functional programming in which you pass functions as an argument to another functions
java supports functional programming in a way by using interfaces and has many built-in interfaces to ease-up the process
i recommend you to take a look at java.util.function package
now lets get on to your code
public void something(Supplier<Void> function) {
boolean condition = true; //use this boolean to control your loop
while (condition) {
Random myrand = new Random();
int number = myrand.nextInt(10 - 1) + 1;
switch (number) {
case 1:
function.get();
break;
case 2:
function.get();
break;
}
}
}
and you can call your "something" like this
public void Call() {
//if you want to declare the function only once
something(new Supplier<Void>() {
#Override
public Void get() {
System.out.println("the job is done!");
return null;
}
});
// if you already have a class implementing supplier
something(new MyFunction());
}
not that the Supplier interface is used because your function didn't have any inputs
you can also use Consumer, BiConsumer, Function, BiFunction .... for functions with inputs
The following code repeatedly calls the runSomeMethod() method for a random number of times.
Use a for loop:
public void something() {
Random myrand = new Random();
int number = myrand.nextInt(10 - 1) + 1;
for(int i=0 ; i<number ; i++) {
runSomeMethod();
}
}
concerned about your CASE syntax used
Solution goes as follows --> keep looping in a while loop
public void something {
boolean condition = true; // toggle this condition boolean to FALSE, when you want to break the loop
while(condition){
Random myrand = new Random();
int number = myrand.nextInt(10 - 1) + 1;
switch(number)
case 1;
Do something and on completion go back and start running the something method again.
break;
case 1;
Do something and on completion go back and start running the something method again.
break;
}
}
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 was looking to randomize the way certain methods are called, so that each one is only called once per instance and every single method is called.
So say one instance they are called in the order:
method2
method4
method3
method1
but in the next instance they are called in a different order:
method3
method2
method1
method4
The code that I have to randomize the order looks like this:
public void randomCalls(){
int[] order = new int[4];
for(int i=0; i<order.length; i++){
order[i]=nextNumber(order);
}
}
public int nextNumber(int[] array){
Random r = new Random();
int x = r.nextInt();
for(int i=0; i<array.length; i++){
if(arrayHasNumber(array,x)){
x = nextNumber(array);
}
}
return x;
}
public boolean arrayHasNumber(int[] array, int x){
for(int i=0;i<array.length;i++){
if(array[i]==x){
return true;
}
}
return false;
}
Based on #Aurand suggestion, you can have a switch that will call your methods and a List<Integer> that will contain the indexes of the methods you want to invoke, then shuffle the list elements using Collections.shuffle and calling the switch to call your methods. Code sample:
final int METHODS_QUANTITY = 4;
List<Integer> lstIndexes = new ArrayList<Integer>();
for(int i = 1; i <= METHODS_QUANTITY; i++) {
lstIndexes.add(i);
}
//you can change the condition for the number of times you want to execute it
while(true) {
Collections.shuffle(lstIndexes);
for(Integer index : lstIndexes) {
switch(index) {
case 1: method1(); break;
case 2: method2(); break;
case 3: method3(); break;
case 4: method4(); break;
}
}
}
Still, the question stands: why would you need this on real world application?
Something like
LinkedList methods
methods.add(1)
methods.add(2)
....
for(i=0; i<methods.size;i++)
r = random.next(methods.size)
switch(methods.get(r)) {
case 1: method1()
case 2: method2()
...
methods.remove(methods.get(r)
My tip would be to go for an ArrayList & thrown in all the method names during initialization.
Then get a random number using random(list.size()) and pop that element out from the ArrayList.
Use a switch case, and whatever method name has popped out, call that method.
Keep doing this, till the list becomes empty.
Possibly you must retain the states (orders in which the calls were made) in an internal variable or in an array (in case you want to have all of them). And then tune your call site to use this state variable.
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;
}
}
I'm implementing a DFA as close as I can to the formal definition as a learning exercise (and blogging material)
I planned on using a java.util.Set where a set is involved in the definition.
The definition involves a set of tuples to define the legal state transitions: (state,symbol) -> nextState.
I have a Transition class with members state, symbol and nextState. I have implemented equals() and hashCode() to indicate that two Transitions are equal if they match on state and symbol. I then have a java.util.Set of Transition instances.
In my processing algorithm, I have the current state when I read the next symbol. I anticipated building a Transition object using these two to pull out the matching Transition from the Set, which would then tell me the next state, and I can iterate.
But - I don't see any way of extracting a member of a java.util.Set for further use. I can remove(Object o), but that just return boolean.
What am I doing wrong?
Set is probably not what you want to use for this. My recommendation would be to use a List< Transition>, or possibly a Map< State,List< Transition>>. I'm not sure which would be better without actually building it and doing some benchmarking.
It sounds as though your overriding of equals() and hashCode() is dubious, because the original transition matches the one in the set according to equals() and yet the two are not interchangeable (otherwise you would just use the new transition in place of the original.)
You probably want a class that is just a combination of state and symbol with no other attributes, and use that as a key in a Map. Alternatively you could use a Map<State, Map<Symbol, State>>
I agree with Matthew Brubaker that Set is probably not what you need. You might want to try enums instead; see the Java Glossary for an example.
Can't you accomplish this without having some external collection of states, or even the Transistion objects? If the State class is defined like:
public class State
{
private Map<Symbol, State> transitions = new HashMap<Symbol, State>();
public State() { /* populate transitions somehow */ }
public State nextState(Symbol symbol) { return transitions.get(symbol); }
}
Then, if you have a reference to the initial state, you can just move from state to state like this:
State initial = getInitialStateSomehow();
State second = initial.nextState(SYMBOL_1);
State third = initial.nextState(SYMBOL_2); // etc...
Yeah I'm kind of confused about why would even need a collection at all.
For a simple state machine you can just use static integers and a case statement to do your state machine like this:
int STATE1 = 1;
int STATE2 = 2;
int STATE3 = 3;
int STATE4 = 4;
int currentstate = STATE1 ;
int input = nextInput();
while(currentstate != STATE4 ){
switch(input){
case STATE1:
if(input == 'a') currentstate = STATE2;
break;
case STATE2:
if(input == 'b') currentstate = STATE3;
else currentstate = STATE1;
break;
case STATE3:
if(input == 'c') currentstate = STATE4;
else currentstate = STATE1;
}
}
That's a basic state machine that will look for any string containing 'abc'. You could easily extend that too look for ab*c or whatever you want.
So what if you want a dynamic state machine, built at runtime? Well, I've done this too. It's not too hard. What I did is create a state class with a list of transitions. Each transition has a pointer to the next state, and the criteria to link on.
So for example, STATE1 would have a transition with the criteria 'a' and a pointer to some object that represents STATE2. The code would look check the criteria (which could be an object that takes an int as a parameter and returns true or false if it matches) and if the criteria matched, it would move the state pointer to the state pointed too by the transition.
The code could look something like ths
public void move(int input){
for(transition t : currentState.transitions){
if(t.getCriteria().matches(input)){
currentState = t.getNextState();
break;
}
}
}
If you just want to implement a pattern matching engine, a State Design Pattern might be unnecessary since the patter is unlikely to change. As Chad has pointed out, using a switch to encode the transition function is completely acceptable in such cases.
Here's an example of a nondeterministic pattern matching automaton that uses sets:
public boolean validate() {
Set<Integer> currentStates = new HashSet<Integer>();
final Set<Integer> acceptingStates = new HashSet<Integer>();
currentStates.add(0); // Initial state.
acceptingStates.add(1);
acceptingStates.add(3);
acceptingStates.add(6);
for (int i = 0; i < getInput().length(); i++) {
char c = getInput().charAt(i);
Set<Integer> newStates = new HashSet<Integer>();
for (int state : currentStates) {
switch (state) {
case 0:
if (c == 'a')
newStates.add(1);
break;
case 1:
if (c == 'b') {
newStates.add(2);
newStates.add(4);
}
break;
case 2:
if (c == 'b')
newStates.add(3);
break;
case 3:
if (c == 'b')
newStates.add(2);
break;
case 4:
if (c == 'b')
newStates.add(5);
break;
case 5:
if (c == 'b')
newStates.add(6);
break;
case 6:
if (c == 'b')
newStates.add(4);
break;
}
}
if (newStates.size() == 0)
return false;
currentStates = newStates;
System.out.printf("Character read: %c\n", c);
System.out.printf("Current states: ");
printStates(currentStates);
}
for (int state : acceptingStates)
if (currentStates.contains(state))
return true;
return false;
}
This automaton recognizes input words of the regular language described by the pattern "a(bb*|bbb*)", i.e. an “a” followed by either a multiple of two or a multiple of three many “b”s.