How to use greater than or equal in a switch statement - java

What is the best way to check if variable is bigger than some number using switch statement? Or you reccomend to use if-else? I found such an example:
int i;
if(var1>var2) i = 1;
if(var1=var2 i = 0;
if(var1<var2) i = -1;
switch (i);
{
case -1:
do stuff;
break;
case 0:
do stuff;
break;
case 1:
do stuff;
break;
}
What can you tell a novice about using "greater than or equal" in switch statements?

Not sure if this is what you're asking, but you could do it this way:
int var1;
int var2;
int signum = Long.signum((long)var1 - var2);
switch(signum) {
case -1: break;
case 0: break;
case 1: break;
}

I would strongly recommend a if(var1>var2){}else if (var1==var2) {} else {} construct. Using a switch here will hide the intent. And what if a break is removed by error?
Switch is useful and clear for enumerated values, not for comparisons.

First a suggestion: switch as it states should only be used for switching and not for condition checking.
From JLS switch statements
SwitchStatement:
switch ( Expression ) SwitchBlock
Expressions convertible to int or Enum are supported in the expression.
These labels are said to be associated with the switch statement, as
are the values of the constant expressions (§15.28) or enum constants
(§8.9.1) in the case labels.
Only constant expressions and Enum constants are allowed in switch statements for 1.6 or lower with java 7 String values are also supported. No logical expressions are supported.
Alternatively you can do as given by #Stewart in his answer.

Java only supports direct values, not ranges in case statements, so if you must use a switch, mapping to options first, then switching on that, as in the example you provide is your only choice. However that is quite excessive - just use the if statements.

A switch statement is for running code when specific values are returned, the if then else allows you to select a range of values in one statement. I would recommend doing something like the following (though I personnally prefer the Integer.signum method) should you want to look at multiple ranges:
int i;
if (var1 > var2) {
i = 1;
}
else if (var1 == var2) {
i = 0;
}
else {
i = -1;
}

You're better off with the if statements; the switch approach is much less clear, and in this case, your switch approach is objectively wrong. The contract for Comparable#compareTo does not require returning -1 or 1, just that the value of the returned int be negative or positive. It's entirely legitimate for compareTo to return -42, and your switch statement would drop the result.

If one variable's value is used, use switch. If multiple variables are in play, use if. In your stated problem, it should be if.

Unfortunately you cannot do that in java. It's possible in CoffeeScript or other languages.
I would recommend to use an if-else-statement by moving your "do stuff" in extra methods. In that way you can keep your if-else in a clearly readable code.

Related

Behavior of switch statement with the default block at the top

I found one interesting way to use a switch statement in Java, and I can't catch all logic.
Can someone help to understand all details in depth?
Here is code:
private static int counter = 0;
public static Shape randomFactory() {
int xVal = rand.nextInt(100);
int yVal = rand.nextInt(100);
int dim = rand.nextInt(100);
switch (counter++ % 3) {
default:
case 0:
return new Circle(xVal, yVal, dim);
case 1:
return new Square(xVal, yVal, dim);
case 2:
return new Line(xVal, yVal, dim);
}
}
In general I understand this logic,
What exactly default mean here:
switch (counter++ % 3) {
default:
And how does switch (counter++ % 3) find equals case? And here isn't any brake presented.
Any suggestions?
default marks the block that would get executed if the switch expression does not match any case labels. In your example, default contains no break, so it would fall through and execute the same code as for case 0.
Note that, since you have a case label for every possible value of the switch expression, the default is effectively a no-op.
In your case you are using default block at the very beginning of case statement, which is a bit strange since default means that this part of code will execute if none of the case conditions have matched. You should also check about fall through. You avoided it with returns, but it is usually done with break.
switch (counter++ % 3) calculates first counter++ % 3 and then matches it with appropriate case.
The default clause is useless here: due to your %3 it should never happen.
Would you modify the %3 to %4 it would catch some data, but as there is neither a break nor a return statement it would execute just like case 0.
default:
It simply means of none of the conditions in switch statement are matched code corresponding to default will be executed.
default will execute when there is no matching in case.In this case default is useless since it will never execute. Consider the following case.
switch(input){
case 1:
// do something
break;
case 2:
// do something
break;
default:
// if input is not 1 or 2 this will execute.
break;
}
Default is one of the switch labels which contains statements to execute if none of the other labels match. From JLS §14.11:
At most one default label may be associated with the same switch statement.
If no case matches but there is a default label, then all statements after the matching default label in the switch block, if any, are executed in sequence. If all these statements complete normally, or if there are no statements after the default label, then the entire switch statement completes normally.
If no case matches and there is no default label, then no further action is taken and the switch statement completes normally.
So in this case default label will do nothing as there always will be a match.
There is no break inside default so it do nothing, it is just example of fallthrough.
Please read about switch statements from here -
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
default means if any case doesn't match with switch condition then default is called.
counter++ % 3 ..your counter was 0 so it will match with case 0.

Won't this just break out of the if statement?

So basically given the below code.
When action = 2; and mode = 1 Will i ever be set to 2?
I am working on a colleagues code, and it is written like this, but I thought that break would just skip the if and continue the rest of case 2. So basically the if statement is pointless.
switch(action){
case 1: i = 1; break;
case 2: if(mode == 1)
{
break;
}
i = 2;
break;
case 3: i = 3; break;
Ive rewritten this as:
case 2: if(mode != 1)
i = 2;
break;
But it is not the only place, and some more complex. If im going to refactor it I need some info that I am correct.
There's no such a thing as an "if loop." Break can never refer to an "if" statement.
See Wasserman's answer for a pointer to the language specification.
Also, assuming that 1 <= action <= 3, your code simplifies to:
if(! (action == 2 && mode == 1)) {
i = action;
}
JLS section 14.15:
A break statement transfers control out of an enclosing statement.
BreakStatement:
break Identifieropt ;
A break statement with no label attempts to transfer control to the innermost enclosing switch, while, do, or for statement (emphasis added) of the immediately enclosing method or initializer block; this statement, which is called the break target, then immediately completes normally.
your refactoring is correct if that's what you want to know.
If action == 2 and mode == 1, i = 2 will not be executed (why you don't test it? It would be faster than asking here).
But your improvement is anyways cleaner, I would use it.

Poor performance of many if-else statements in Java

I have a method that checks all of the combinations of 5 different conditions with 32 if-else statements (think of the truth table). The 5 different letters represent methods that each run their own regular expressions on a string, and return a boolean indicating whether or not the string matches the regex. For example:
if(A,B,C,D,E){
}else if(A,B,C,D,!E){
}else if(A,B,C,!D,!E){
}...etc,etc.
However, it is really affecting the performance of my application (sorry, I can't go into too many details). Can anyone recommend a better way to handle such logic?
Each method using a regular expression looks like this:
String re1 = "regex here";
Pattern p = Pattern.compile(re1, Pattern.DOTALL);
Matcher m = p.matcher(value);
return m.find();
Thanks!
You can try
boolean a,b,c,d,e;
int combination = (a?16:0) + (b?8:0) + (c?4:0) + (d?2:0) + (e?1:0);
switch(combination) {
case 0:
break;
// through to
case 31:
break;
}
represent each condition as a bit flag, test each condition once, and set the relevant flag in a single int. then switch on the int value.
int result = 0;
if(A) {
result |= 1;
}
if(B) {
result |= 2;
}
// ...
switch(result) {
case 0: // (!A,!B,!C,!D,!E)
case 1: // (A,!B,!C,!D,!E)
// ...
}
All the above answers are wrong, because the correct answer to an optimisation question is: Measure! Use a profiler to measure where your code is spending its time.
Having said that, I'd be prepared to bet that the biggest win is avoiding compiling the regexes more than once each. And after that, as others suggested, only evaluate each condition once and store the results in boolean variables. So thait84 has the best answer.
I'm also prepared to bet jtahlborn and Peter Lawrey's and Salvatore Previti suggestions (essentially the same), clever though they are, will get you negligible additional benefit, unless you're running on a 6502...
(This answer reads like I'm full of it, so in the interests of full disclosure I should mention that I'm actually hopeless at optimisation. But measuring still is the right answer.)
Without knowing more details, it might be helpful to arrange the if statements in such a way that the ones which do the "heavy" lifting are executed last. This is making the assumption that the other conditionals will be true thereby avoiding the "heavy" lifting ones all together. In short, take advantage of short-circuits if possible.
Run the regex once for each string and store the results in to booleans and just do the if / else on the booleans instead of running the regex multiple times. Also, if you can, try to re-use a pre-compiled version of your regex and re-use this.
One possible solution: use a switch creating a binary value.
int value = (a ? 1 : 0) | (b ? 2 : 0) | (c ? 4 : 0) | (d ? 8 : 0) | (e ? 16 : 0);
switch (value)
{
case 0:
case 1:
case 2:
case 3:
case 4:
...
case 31:
}
If you can avoid the switch and use an array it would be faster.
Maybe partition it into layers, like so:
if(A) {
if(B) {
//... the rest
} else {
//... the rest
}
} else {
if(B) {
//... the rest
} else {
//... the rest
}
}
Still, feels like there must be a better way to do this.
I have a solution with EnumSet. However it's too verbose and I guess I prefer #Peter Lawrey's solution.
In Effective Java by Bloch it's recommended to use EnumSet over bit fields, but I would make an exception here. Nonetheless I posted my solution because it could be useful for someone with a slightly different problem.
import java.util.EnumSet;
public enum MatchingRegex {
Tall, Blue, Hairy;
public static EnumSet<MatchingRegex> findValidConditions(String stringToMatch) {
EnumSet<MatchingRegex> validConditions = EnumSet.noneOf(MatchingRegex.class);
if (... check regex stringToMatch for Tall)
validConditions.add(Tall);
if (... check regex stringToMatch for Blue)
validConditions.add(Blue);
if (... check regex stringToMatch for Hairy)
validConditions.add(Hairy);
return validConditions;
}
}
and you use it like this:
Set<MatchingRegex> validConditions = MatchingRegex.findValidConditions(stringToMatch);
if (validConditions.equals(EnumSet.of(MatchingRegex.Tall, MathchingRegex.Blue, MatchingRegex.Hairy))
...
else if (validConditions.equals(EnumSet.of(MatchingRegex.Tall, MathchingRegex.Blue))
...
else if ... all 8 conditions like this
But it would be more efficient like this:
if (validConditions.contains(MatchingRegex.Tall)) {
if (validConditions.contains(MatchingRegex.Blue)) {
if (validConditions.contains(MatchingRegex.Hairy))
... // tall blue hairy
else
... // tall blue (not hairy)
} else {
if (validConditions.contains(MatchingRegex.Hairy))
... // tall (not blue) hairy
else
... // tall (not blue) (not hairy)
} else {
... remaining 4 conditions
}
You could also adapt your if/else to a switch/case (which I understand is faster)
pre-generating A,B,C,D and E as booleans rather than evaluating them in if conditions blocks would provide both readability and performance. If you're also concerned about performance the different cases, you may organise them as a tree or combine them into a single integer (X = (A?1:0)|(B?2:0)|...|(E?16:0)) that you'd use in a switch.

Java Question: Is it possible to have a switch statement within another one?

I have a yes or no question & answer. I would like to ask another yes or no question if yes was the answer. My instructor wants us to use charAt(0) as input for the answer.
Is it possible to have a switch statement within another one (like a nested if statement)?
EDIT: Here is a sample of my pseudo code =
display "Would you like to add a link (y = yes or n = no)? "
input addLink
switch (link)
case 'y':
display "Would you like to pay 3 months in advance " + "(y = yes or n = no)?"
input advancePay
switch(advPay)
case 'y':
linkCost = 0.10 * (3 * 14.95)
case 'n'
linkCost = 14.95
case 'n'
linkCost = 0.00
Yes, but don't. If you need a further level of logic like that, place the second Switch in its own method with a descriptive name.
EDIT: By the example you've added, you've got two Boolean conditions. I would recommend against using switch at all, using if & else conditionals instead. Use (STRING.charAt(0) == 'y') as your test case, or something methodical like boolean isY(final String STRING) { return (STRING.charAt(0) == 'y' || STRING.charAt(0) == 'Y'); }
Yes. Switches break the language block statement pattern, but this is mainly because of C/C++ from which the switch statement used by Java is based.
In all three languages, the switch statement takes the following form:
switch(variable) {
case n:
statement 1;
statement n;
(optional) break;
case n+1:
statement 1;
statement n;
(optional) break;
// Optionally more statements
(optional) default:
statement 1;
statement n;
}
Because a switch statement breaks the traditional language pattern, many programmers wrap their multiple statements in a case using the traditional block style: { }
This is because most constructs in all three languages allow block style statements to be considered as one statement, but the switch statement does not require block style to execute multiple statements in a single case.
Without the break statement separating each case, there will be "fall through" - if case n was matched and did not have a break, the code under it (case n + 1) would be executed - if case n + 1 did not have a break and was matched, the default code would execute, if neither had a break, when matching case n, the code for case n, case n+1 and default would be executed.
The default is optional, and specifies a default action for a switch statement to execute. Typically, the default condition is either a generic handler, or a good place to throw an exception if the value could not logically be any other than the values in the switch statement.
To illustrate a switch statement executing inside a switch statement, take a look at this contrived example:
String message = null;
int outerVariable = getOuterVariable();
switch(outerVariable) {
case n:
statement 1;
statement n;
break;
case n+1:
int innerVariable = getInnerVariable();
switch(innerVariable) {
case 1:
message = "IT WAS 1";
break;
default:
message = "WHY WOULD YOU DO THIS? OH THE HUMANITY!";
}
break;
// Optionally more statements
(optional) default:
statement 1;
statement n;
}
It is possible, but that would be very convoluted and hard to read. There's almost certainly a better way, such as calling a method within the first switch statement and doing any more necessary processing (including another switch if necessary) in that method.
Most programming languages are orthogonal. That means, using a feature usually does not depend on the location, if meaningful.
For example, you cannot declare a local variable as public.

Optimizing if-else /switch-case with string options

What modification would bring to this piece of code? In the last lines, should I use more if-else structures, instead of "if-if-if"
if (action.equals("opt1"))
{
//something
}
else
{
if (action.equals("opt2"))
{
//something
}
else
{
if ((action.equals("opt3")) || (action.equals("opt4")))
{
//something
}
if (action.equals("opt5"))
{
//something
}
if (action.equals("opt6"))
{
//something
}
}
}
Later Edit: This is Java. I don't think that switch-case structure will work with Strings.
Later Edit 2:
A switch works with the byte, short,
char, and int primitive data types. It
also works with enumerated types
(discussed in Classes and Inheritance)
and a few special classes that "wrap"
certain primitive types: Character,
Byte, Short, and Integer (discussed
in Simple Data Objects ).
Even if you don't use a switch statement, yes, use else if to avoid useless comparison: if the first if is taken, you don't want all others ifs to be evaluated here since they'll always be false. Also you don't need indenting each if making the last block being so indented that you can't see it without scrolling, the following code is perfectly readable:
if (action.equals("opt1")) {
}
else if (action.equals("opt2")) {
}
else if (action.equals("opt3")) {
}
else {
}
Use a dictionary with string as key type and delegates* as value type.
- Retrieving the method from using the string will take O(1+load).
Fill the dictionary within the class's constructor.
Java does not support delegate, so as a work around you may need to define a few inner classes - one for each case and pass the instance of the inner classes instead of the methods as values.
Use a switch statement assuming your language supports switching on a string.
switch(action)
{
case "opt6":
//
break;
case "opt7":
//
...
...
...
}
There are a number of ways to do this in Java, but here's a neat one.
enum Option {
opt1, opt2, opt3, opt4, opt5, opt6
}
...
switch (Option.valueOf(s)) {
case opt1:
// do opt1
break;
case opt2:
// do opt2
break;
case opt3: case opt4:
// do opt3 or opt4
break;
...
}
Note that valueOf(String) will throw an IllegalArgumentException if the argument
is not the name of one of the members of the enumeration. Under the hood, the implementation of valueOf uses a static hashmap to map its String argument to an enumeration value.
You can use a switch.
switch (action)
{
case "opt3":
case "opt4":
doSomething;
break;
case "opt5":
doSomething;
break;
default:
doSomeWork;
break;
}
It could help if you specified the language... As it looks like C++, you could use switch.
switch (action) {
case "opt1":
// something
break;
case "opt2":
// something
break;
...
}
And in case you want to use if statements, I think you could improve readability and performance a bit if you used "else if" without the curly braces, as in:
if (action.equals("opt1")) {
//something
} else if (action.equals("opt2")) {
//something
} else if ((action.equals("opt3")) || (action.equals("opt4"))) {
//something
} else if (action.equals("opt5")) {
//something
} else if (action.equals("opt6")) {
//something
}
I think some compilers can optimize else if better than a else { if. Anyways, I hope I could help!
I would just clean it up as a series of if/else statements:
if(action.equals("opt1"))
{
// something
}
else if (action.equals("opt2"))
{
// something
}
else if (action.equals("opt3"))
{
// something
}
etc...
It depends on your language, but it looks C-like, so you could try a switch statement:
switch(action)
{
case "opt1":
// something
break;
case "opt2":
// something
break;
case "opt3":
case "opt4":
// something
break;
case "opt5":
// something
break;
case "opt6":
// something
break;
}
However, sometimes switch statements don't provide enough clarity or flexibility (and as Victor noted below, will not work for strings in some languages). Most programming languages will have a way of saying "else if", so rather than writing
if (condition1)
{
...
}
else
{
if (condition2)
{
...
}
else
{
if (condition3)
{
...
}
else
{
// This can get very indented very fast
}
}
}
...which has a heap of indents, you can write something like this:
if (condition1)
{
...
}
else if (condition2)
{
...
}
else if (condition3)
{
...
}
else
{
...
}
In C/C++ and I believe C#, it's else if. In Python, it's elif.
The answers advising the use of a switch statement are the way to go. A switch statement is much easier to read than the mess of if and if...else statements you have now.
Simple comparisons are fast, and the //something code won't executed for all but one case, so you can skip "optimizing" and go for "maintainability."
Of course, that's assuming that the action.equals() method does something trivial and inexpensive like a ==. If action.equals() is expensive, you've got other problems.
Procedural switching like this very often is better handled by polymorphism - rather than having an action represented by a string, represent an action by an object who has a 'something' method you can specialise. If you find you do need to map a string to the option, use a Map<String,Option>.
If you want to stick to procedural code, and the options in your real code really are all "optX":
if ( action.startsWith("opt") && action.length() == 4 ) {
switch ( action.charAt(3) ) {
case '1': something; break;
case '2': something; break;
case '3': something; break;
...
}
}
which would be OK in something like a parser ( where breaking strings up is part of the problem domain ), and should be fast, but isn't cohesive ( the connection between the object action and the behaviour is based on the parts of its representation, rather than anything intrinsic in of the object ).
In fact this depends on branch analysis. If 99% of your decisions are "opt1" this code is already pretty good. If 99% of your decisions are "opt6" this code is ugly bad.
If you got often "opt6" and seldom "opt1" put "opt6" in the first comparison and order the following comparisons according to the frequency of the strings in your execution data stream.
If you have a lot of options and all have equal frequency you can sort the options and split them into a form of a binary tree like this:
if (action < "opt20")
{
if( action < "opt10" )
{
if( action == "opt4" ) {...}
else if( action == "opt2" ) {...}
else if( action == "opt1" ) {...}
else if( action == "opt8" ) {...}
}
}
else
{
if( action < "opt30 )
{
}
else
{
if( action == "opt38" ) {...}
else if( action == "opt32" ) {...}
}
}
In this sample the the range splits reduces the needed comparisons for "opt38" and "opt4" to 3. Doing this consequent you get log2(n) +1 comparisons in every branch. this is best for equal frequencies of the options.
Don't do the binary spit to the end, at the end use 4-10 "normal" else if constructs that are ordered by the frequency of the options. The last two or three levels in a binary tree don't take much advance.
Summary
At least there are two optimizations for this kind of comparisons.
Binary Decision Trees
Ordering due to the frequency of the options
The binary decision tree is used for large switch-case constructs by the compiler. But the compiler don't know anything about frequencies of an option. So the ordering according to the frequencies can be a performance benefit to the use of switch-case if one or two options are much more frequent than others. In this case this is a workaround:
if (action == "opt5") // Processing a frequent (99%) option first
{
}
else // Processing less frequent options (>1%) second
{
switch( action )
{
case "opt1": ...
case "opt2": ...
}
}
Warning
Don't optimize your code until you have done profiling and it is really necessary. It is best to use switch-case or else-if straight forward and your code keeps clean and readable. If you have optimized your code, place some good comments in the code so everybody can understand this ugly peace of code. One year later you won't know the profiling data and some comments will be really helpful.
If you find the native java switch construct is too much limiting give a glance to the lambdaj Switcher that allows to declaratively switch on any object by matching them with some hamcrest matchers.
Note that using strings in the cases of a switch statement is one of the new features that will be added in the next version of Java.
See Project Coin: Proposal for Strings in switch

Categories

Resources