use relational operators in switch - java

Is there a way to use relational operators (<,<=,>,>=) in a switch statement?
int score = 95;
switch(score) {
case (score >= 90):
// do stuff
}
the above example (obviously) doesn't work

No you can not.
From jls-14.11
The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.
Relational operators (<,<=,>,>=) results in boolean and which is not allowded.
All of the following must be true, or a compile-time error occurs:
Every case constant expression associated with a switch statement must be assignable (§5.2) to the type of the switch Expression.
No two of the case constant expressions associated with a switch statement may have the same value.
No switch label is null.
At most one default label may be associated with the same switch statement.

This might help you if you need to do it with switch itself,
char g ='X';
int marks = 65;
switch(marks/10)
{
case 1:
case 2:
case 3:
case 4: g = 'F';
break;
case 5: g = 'E';
break;
case 6: g = 'D';
break;
case 7: g = 'C';
break;
case 8: g = 'B';
break;
case 9:
case 10: g = 'A';
break;
}
System.out.println(g);
It works this way,
if(marks<50)
g='F';
else if(marks<60)
g='E';
else if(marks<70)
g='D';
else if(marks<80)
g='C';
else if(marks<90)
g='B';
else if(marks<=100)
g='A';

Unfortunately NO, though you can use case fall (kind of hacky) by grouping multiple case statements without break and implement code when a range ends:
int score = 95;
switch(score) {
..
case 79: System.out.println("value in 70-79 range"); break;
case 80:
..
case 85: System.out.println("value in 80-85 range"); break;
case 90:
case 91:
case 92:
case 93:
case 94:
case 95: System.out.println("value in 90-95 range"); break;
default: break;
}
IMHO, using if would be more appropriate in your particular case.

It will never work. You should understand what switch does in the first place.
It will execute the statements falling under the case which matches the switch argument.
In this case, score is an argument which is 95 but score>=90 will always evaluate to either true or false and never matches an integer.
You should use if statements instead.
Also Java doesn't allow booleans in switch cases so yea.

Simply NO
int score = 95;
switch(score) {
case (score >= 90):
// do stuff
}
You are passing a int value to switch. So the case's must be in int values, where
(score >= 90)
Turns boolean.
Your case is a good candidaate for if else

The docs for switch-case statement state:
a switch statement tests expressions based only on a single integer, enumerated value, or String object.
So there is no boolean. Doing so would make no sence since you only have two values: true or false.
What you could do is write a method which checks the score and then returns a one of the types switch can handle
For example:
enum CheckScore {
SCORE_HIGHER_EQUAL_90,
...
}
public CheckScore checkScore(int score) {
if(score >= 90) {
return SCORE_HIGHER_EQUAL_90;
} else if(...) {
return ...
}
}
and then use it in your switch:
switch(checkScore(score)) {
case SCORE_HIGHER_EQUAL_90:
// do stuff
}
... Or You could just use if, else-if, else directly!

Obviously, this is not possible as a language construct. But, just for fun, we could implement it by ourselves!
public class Switch<T, V> {
public static interface Action<V> {
V run();
}
private final T value;
private boolean runAction = false;
private boolean completed = false;
private Action<V> actionToRun;
public Switch(T value) {
this.value = value;
}
static public <T, V> Switch<T, V> on(T value) {
return new Switch<T, V>(value);
}
public Switch<T, V> ifTrue(boolean condition) {
runAction |= condition;
return this;
}
public Switch<T, V> ifEquals(T other) {
return ifTrue(value.equals(other));
}
public Switch<T, V> byDefault(Action<V> action) {
this.actionToRun = action;
return this;
}
public Switch<T, V> then(Action<V> action) {
if (runAction && !completed) {
actionToRun = action;
completed = true;
}
return this;
}
public V getResult() {
if (actionToRun == null) {
throw new IllegalStateException("none of conditions matched and no default action was provided");
}
return actionToRun.run();
}
}
Switch accepts any value to switch on and then provides functionality to match over boolean conditions (ifTrue method) or by exact matches (ifEquals method). Providing a value to switch on is needed just for the latter feature.
After building the conditions, user invokes getResult to obtain the result.
For example, we could create a method that tells us what it thinks about our score:
String tellMeMyScore(int score) {
return Switch.<Integer, String> on(score).byDefault(new Action<String>() {
public String run() {
return "really poor score";
}
}).ifTrue(score > 95).then(new Action<String>() {
public String run() {
return "you rock!";
}
}).ifTrue(score > 65).then(new Action<String>() {
public String run() {
return "not bad, not bad";
}
}).ifEquals(42).then(new Action<String>() {
public String run() {
return "that's the answer!";
}
}).getResult();
}
This simple test:
for (int score : new int[] { 97, 85, 66, 55, 42, 32, 4 }) {
System.out.println(score + ": " + tellMeMyScore(score));
}
Prints out:
97: you rock!
85: not bad, not bad
66: not bad, not bad
55: really poor score
42: that's the answer!
32: really poor score
4: really poor score

Related

How to change this code from switch case to if else?

How to use if-else to write this code?
I'd like to know the difference between the two methods. Thanks
switch (status) {
case AIRCRAFT_CARRIER_HIT:
if (this.getFleet().updateFleet(ShipType.ST_AIRCRAFT_CARRIER))
result[1] = "a";
break;
case BATTLESHIP_HIT:
if (this.getFleet().updateFleet(ShipType.ST_BATTLESHIP))
result[1] = "a";
break;
case CRUISER_HIT:
if (this.getFleet().updateFleet(ShipType.ST_CRUISER))
result[1] = "a";
break;
case DESTROYER_HIT:
if (this.getFleet().updateFleet(ShipType.ST_DESTROYER))
result[1] = "a";
break;
case SUB_HIT:
if (this.getFleet().updateFleet(ShipType.ST_SUB))
result[1] = "a";
break;
default:
result[1] = null;
In an if statement, the enum has to be in full form and the variable compared to has to be mentioned in all the conditions. I don't know the name of the enum, but I'll guess it's Status. In that case you'd write
if (status == Status.AIRCRAFT_CARRIER_HIT) {
if (this.getFleet().updateFleet(ShipType.ST_AIRCRAFT_CARRIER)) {
result[1] = "a";
}
} else if (status == Status.BATTLESHIP_HIT) {
// etc.
} else {
result[1] = null;
}
your switch statement can be written as below with if/else (assuming the variables AIRCRAFT_CARRIER_HIT etc are final and assigned a value at compile time, eg final int AIRCRAFT_CARRIER_HIT = 3 :
if (status == AIRCRAFT_CARRIER_HIT ) {
...
}
else if (status == BATTLESHIP_HIT) {
...
}
…
…
else {
// default case
}
for differences and pros/cons of each approach you can check here for example

Shortening a switch case method for JLabels

I have a method that takes in a Briefcase, and the user's selected briefcase number which holds a value. For example .getValue1() returns a JLabel. What can I do to shorten this switch case so I am not repeating code?
public void removeValueDisplay(Briefcase briefcase, int caseNum) {
switch (Model.briefcases[caseNum - 1].getValue())
{
case 1:
view.getValue1().setEnabled(false);
break;
case 2:
view.getValue2().setEnabled(false);
break;
case 5:
view.getValue5().setEnabled(false);
break;
case 10:
view.getValue10().setEnabled(false);
break;
case 25:
view.getValue25().setEnabled(false);
break;
}
}
There are 26 cases in total, which I haven't included in this code
Create an array of JLabel in your Briefcase class to store your labels. Then an accessor for all at once:
public JLabel[] getValues();
Or to retrieve only the one you want:
public JLabel getValue(int number);
Thanks for your help everyone. This how I've shortened my code:
public void removeValueDisplay(int caseNum) {
for (int i = 0; i < Model.briefcases.length; ++i) {
if(Model.briefcases[caseNum - 1].getValue() == Model.values[i]) {
view.getValueLabels()[i].setEnabled(false);
}
}

Highest card wins is my program and now I want to compare cards

I am using Android studio for my highest card wins Game. I have three java classes called Cards, Deck, Gamelogic. everything is going good so far but I am just having a little trouble starting a function for my comparing cards method. This is what I have so far ...
import android.graphics.Color;
/**
* Created by azib2 on 12/1/2016.
*/
enum Suite {
Heart, diamond, spades, clubs;
public String toString()
{
switch (this) {
case Heart:
return "Heart";
case diamond:
return "diamond";
case spades:
return "spades";
case clubs:
return "clubs";
default:
return "Wrong type";
}
}
public String symbol(){
switch (this) {
case Heart:
return "\u2764";
case diamond:
return "\u2666";
case spades:
return "\u2660";
case clubs:
return "\u2663";
default:
return "Wrong type";
}
}
public int colors() {
switch (this) {
case Heart:
case diamond:
return Color.RED;
case spades:
case clubs:
return Color.BLACK;
}
return 0;
}
}
public class Cards {
private int cardnum;
private Suite suitetype;
public Cards(int cardnum, Suite suitetype){
this.cardnum = cardnum;
this.suitetype = suitetype;
}
public String CardType(int num){
switch(num){
case 1: return "A";
case 2: return "2";
case 3 : return"3";
case 4: return "4";
case 5: return "5";
case 6: return "6";
case 7: return "7";
case 8: return "8";
case 9: return "9";
case 10: return "10";
case 11: return "J";
case 12: return "Q";
case 13: return "K";
default: return " error invaild ";
}
}
public void CompareCards(){
}
public int Getcardnum (){
return cardnum;
}
public Suite getsuite(){
return suitetype;
}
}
What should I do to compare cards?
First, I recommend "Cards" be "Card". But I'll stick with "Cards" here.
This seems like a good use-case for Comparable interface:
public class Cards implements Comparable<Cards> {
// Ace lowest:
public int compareTo(Card other) {
return Integer.compare(cardnum, other.cardnum);
}
}
Then to see if one card is higher than another:
if(card.compareTo(otherCard) > 0) { ... }
With this approach, you could even sort a list of cards using:
List<Cards> cards = new ArrayList<Cards>();
// Add all cards desired
Collections.sort(cards);
If you want stable sorting (by both value and suit):
public class Cards implements Comparable<Cards> {
// Ace lowest:
public int compareTo(Card other) {
// Compare by value first
int diff = Integer.compare(cardnum, other.cardnum);
if(diff != 0) return diff;
// Compare by suit
return suitetype.compareTo(other.suitetype);
}
}

Use an array as a case statement in switch

I am trying to do something like this, i.e., use an array in a switch statement. Is it possible in Java? If it isn't, please explain a possible solution.
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
switch (values) {
case [true, false, true, false]:
break;
case [false, false, true, false]:
break;
default:
break;
}
#sᴜʀᴇsʜ ᴀᴛᴛᴀ is right. But I wanted to add something. Since Java 7, switch statements support Strings, so you could do something with that. It is really dirty and I do not recommend, but this works:
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
switch (Arrays.toString(values)) {
case "[true, false, true, false]":
break;
case "[false, false, true, false]":
break;
default:
break;
}
For those concerned about performance: you are right, this is not super fast. This will be compiled into something like this:
String temp = Arrays.toString(values)
int hash = temp.hashCode();
switch (hash)
{
case 0x23fe8da: // Assume this is the hashCode for that
// original string, computed at compile-time
if (temp.equals("[true, false, true, false]"))
{
}
break;
case 0x281ddaa:
if (temp.equals("[false, false, true, false]"))
{
}
break;
default: break;
}
NO, simply you cannot.
SwitchStatement:
switch ( Expression ) SwitchBlock
The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.11
You can't switch on whole arrays. But you could convert to a bit set at the expense of some readability of the switch itself:
switch (values[0] + 2 * values[1] + 4 * values[2] + 8 * values[3])
and use binary literals in your case statements: case 0b0101 is your first one.
Try this solution:
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
if (ArrayUtils.isEquals(values, new boolean[] {true, false, true, false})) {
...
}
else if (ArrayUtils.isEquals(values, new boolean[] {false, false, true, false})) {
...
}
else {
...
}
See docs here.
Yes, you can pass an array to a switch. The catch is that I'm not talking about Java arrays, but a data structure.
An array is a systematic arrangement of objects, usually in rows and columns.
What you are trying to do is implement a system that recognizes different flags and depending on the flags that are turned on or off you take different actions.
Example
A popular implementation of such mechanism is Linux file permissions. Where you have rwx as the "array of flags".
If the whole array is true, you'll see rwx, which means that you have all the permissions. If you are not allowed to perform any action on a file, the whole array is false, you'll see ---.
Implementation
Guess what, you can think of integers as arrays. An integer is represented by an "array of bits".
001 // 1, if on, set x
010 // 2, if on, set w
100 // 4, if on, set r
// putting it all together in a single "array" (integer)
111 // 2^2 + 2^1 + 2^0 = 4 + 2 + 1 = 7
That is why the permission rwx can be represented as a 7
Java snippet:
class Flags {
public static void main(String args[]) {
/**
* Note the notation "0b", for binary; I'm using it for emphasis.
* You could just do:
* byte flags = 6;
*/
byte flags = 0b110; // 6
switch(flags) {
case 0: /* do nothing */ break;
case 3: /* execute and write */ break;
case 6: System.out.println("read and write\n"); break;
case 7: /* grant all permissions */ break;
default:
System.out.println("invalid flag\n");
}
}
}
To know more about using a binary format, check this question: In Java, can I define an integer constant in binary format?
Performance
Saves memory
You don't have to do extra processing, switches or any other type of juggling.
C programs that require to be as efficient as possible use this type of mechanism; they use flags represented with single bits.
No, you cannot, however you can replace the above with the following (dirty I admit) code:
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
switch(makeSuitableForSwitch(values)) {
case 1010:
break;
case 10:
break;
default:
break;
}
private int makeSuitableForSwitch( boolean[] values) {
return (values[0]?1:0)*1000+(values[1]?1:0)*100+(values[2]?1:0)*10+(values[3]?1:0);
}
If you're trying to determine if a set of conditions is true, I'd use bitwise fields instead.
For example,
public class HelloWorld
{
// These are the options that can be set.
// They're final so treated as constants.
static final int A=1<<0, B=1<<1, C=1<<2, D=1<<3 ;
public static void main(String []args)
{
// Now I set my options to have A=true, B=true, C=true, D=false, effectively
int options = A | B | C ;
switch( options )
{
case (A):
System.out.println( "just A" ) ;
break ;
case (A|B):
System.out.println( "A|B" ) ;
break ;
case (A|B|C): // Final int is what makes this work
System.out.println( "A|B|C" ) ;
break ;
default:
System.out.println( "unhandled case" ) ;
break ;
}
}
}
I'd compute a value based on the sequence of the elements in the boolean array, i.e. [true, false, true, true] would evaluate to 1011 and then based on this integer value you can use switch statement.
As of JRE 1.7, you will need to use a hack, I recommend:
Assume values.length <= 64
Convert values to a long representing bitflags
Switch against hexadecimal magic numbers
Java Code Hack:
if(values.length > 64)
throw new IllegalStateException();
long bitflags = 0x0L;
for(int i=0; i< values.length; ++i)
if(values[i])
bitflags |= 0x01L << i;
switch(bitflags) {
case 0xEL: // represents [true, true, true, false]
break;
case 0xAL: // represents [true, false, true, false]
break;
case 0x2L: // represents [false, false, true, false]
break;
default:
break;
}
This answer is not Java, but Haxe because it is possible in it, thanks to pattern matching and has interesting output, which might be useful for you to find a switch that does what you are asking for. Arrays can be matched on fixed length.
I created an demo that compiles to Javascript and Flash. You can see the js-output in the right column.
Demo:
http://try.haxe.org/#86314
class Test {
static function main(){
var array=[true,false,true];
var result=switch(array){
case [true,true,false]: "no";
case [true,false,true]: "yes";
default:"??";
}
#if js
new js.JQuery("body").html(result);
#elseif flash
trace(result);
#end
// ouputs: "yes"
}
}
This is the outputted switch, it uses nested switches. If you play with the cases, you see how the js-ouput changes to have a efficient switch.
(function () { "use strict";
var Test = function() { };
Test.main = function() {
var array = [true,false,true,false];
var result;
switch(array.length) {
case 4:
switch(array[0]) {
case true:
switch(array[1]) {
case false:
switch(array[2]) {
case true:
switch(array[3]) {
case false:
result = "no";
break;
default:
result = "??";
}
break;
default:
result = "??";
}
break;
default:
result = "??";
}
break;
case false:
switch(array[1]) {
case false:
switch(array[2]) {
case true:
switch(array[3]) {
case false:
result = "yes";
break;
default:
result = "??";
}
break;
default:
result = "??";
}
break;
default:
result = "??";
}
break;
}
break;
default:
result = "??";
}
new js.JQuery("body").html(result);
};
var js = {};
var q = window.jQuery;
js.JQuery = q;
Test.main();
})();
Another interesting pattern that you can use underscores. a _ pattern matches anything, so case _: is equal to default, which makes you able to do this:
var myArray = [1, 6];
var match = switch(myArray) {
case [2, _]: "0";
case [_, 6]: "1";
case []: "2";
case [_, _, _]: "3";
case _: "4";
}
trace(match); // 1
http://haxe.org/manual/pattern_matching#array-matching
The answer is NO. The best explain is learn how to use the switch statement.
Here is another approach requiring no imports nor libraries:
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
int mask = buildMask(values);
if (areEquals(mask, true, false, true, false)) {
// ...
} else if (areEquals(mask, false, false, true, false)) {
// ...
} else {
// ...
}
private int buildMask(boolean... values) {
int n = 0;
for (boolean b : values) {
n = (n << 1) | (b ? 1 : 0);
}
return n;
}
private boolean areEquals(int mask, boolean... values) {
return mask == buildMask(values);
}
You can also take a look at how Groovy implements the isCase() methods in Java, use a simpler version that fits your needs. It's possible to put that in an interface and create a DSL to compare any two object in your application.
return isCase(DefaultTypeTransformation.asCollection(caseValue), switchValue);
The relevant code is covered in Lines 877 through Lines 982
#Todor Yes, THIS IS POSSIBLE IN JAVA.
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
String values_asString = Arrays.toString(values);
switch (values_asString) {
case "[true, false, true, false]":
break;
case "[false, false, true, false]":
break;
case "[true, false, false, true]":
System.out.println("YAAAAAAAAAA GOT IT");
break;
default:
break;
}
Here I just converted an array to a string format and then matched it in the switch case.
I would use constant int values that represent the boolean state.
If you use Java 1.7 or above you can use binary literals that are more readable.
public static final int TRUE_FALSE_TRUE_FALSE = 0b1010;
public static final int FALSE_FALSE_TRUE_FALSE = 0b0010;
for Java 1.6 and below use any other int literals, e.g. hex
public static final int TRUE_FALSE_TRUE_FALSE = 0xA;
public static final int FALSE_FALSE_TRUE_FALSE = 0x2;
then create a method that converts a boolean array to an integer bitset. E.g.
public static int toIntBitSet(boolean...values){
int bitset = 0;
for (boolean value : values) {
bitset = (bitset << 1) | (value ? 1 : 0);
}
return bitset;
}
Finally use the constants in your switch statement
boolean[] values = new boolean[]{true, false, true, false};
int bitset = toIntBitSet(values);
switch (bitset) {
case TRUE_FALSE_TRUE_FALSE:
System.out.println(Integer.toBinaryString(bitset));
break;
case FALSE_FALSE_TRUE_FALSE:
System.out.println(Integer.toBinaryString(bitset));
break;
default:
break;
}
Another approach might be to use a java BitSet and a Map that maps to the logic that should be executed depending on the bitset's value.
public static void main(String[] args) throws Exception {
Map<BitSet, Callable<String>> bitSetMap = new HashMap<>();
bitSetMap.put(bitSetValueOf(true, false, true, false), new TrueFalseTrueFalseCallable());
bitSetMap.put(bitSetValueOf(false, false, true, false), new FalseFalseTrueFalseCallable());
boolean[] values = new boolean[]{true, false, true, false};
BitSet bitset = bitSetValueOf(values);
Callable<String> callable = bitSetMap.get(bitset);
if (callable == null) {
callable = new DefaultCallable();
}
String result = callable.call();
System.out.println(result);
}
public static BitSet bitSetValueOf(boolean... values) {
BitSet bitSet = new BitSet();
for (int i = 0; i < values.length; i++) {
bitSet.set(i, values[i]);
}
return bitSet;
}
and implement your logic
class FalseFalseTrueFalseCallable implements Callable<String> {
#Override
public String call() throws Exception {
return "0010";
}
}
class TrueFalseTrueFalseCallable implements Callable<String> {
#Override
public String call() throws Exception {
return "1010";
}
}
class DefaultCallable implements Callable<String> {
#Override
public String call() throws Exception {
return "default value";
}
}

error in the given code for infix to postfix conversion for input containing more than 2 operands

static String convert(String exp)
{
String result="";
Stack s1=new Stack();
for(int i=0;i<exp.length();i++)
{
if(Character.isDigit(exp.charAt(i)))
{{
result=result+exp.charAt(i);
continue;
}
else
{
if(s1.empty())
{
s1.push(exp.charAt(i));
continue;
}
else
{
if(check(exp.charAt(i))>check(exp.charAt(i-1)))
s1.push(exp.charAt(i));
else
{
while(!s1.empty())
{
String a=s1.pop().toString();
result=result+a;
}
s1.push(exp.charAt(i));
}
}
}
}
while(!s1.empty())
{
String p=s1.pop().toString();
result=result+p;
}
return result;
}
static int check(char c)
{
switch (c) {
case '+':
case '-':
return 0;
case '*':
case '/':
return 1;
case '^':
return 2;
default:
throw new IllegalArgumentException("Operator unknown: " + c);
}
}
Here's my code to convert an expression from infix to postfix.
This code is working fine with just 2 operands..for more than 2 operands like 6+9*7 it shows
IllegalArgumentException which I have given in another method to set priorities of operators. Please help me to clarify where am I getting wrong?
Indent your code
In the stack trace:
at Test.convert(Test.java:21)
Is this line:
if(check(exp.charAt(i))>check(exp.charAt(i-1)))
So I think you mean:
if (check(exp.charAt(i)) > check(s1.peek()))
Now "The method check(char) in the type Test is not applicable for the arguments (Object)" is raised, so parameterized your Stack. That is, change:
Stack s1=new Stack();
To (in Java 7):
Stack<Character> s1 = new Stack<>();
You are getting this exception because of your logic. Consider 1+2*3. In this case, when you get 3 below code gets executed:
else
{
if(check(exp.charAt(i))>check(exp.charAt(i-1)))
s1.push(exp.charAt(i));
And check(3) results in
default:
throw new IllegalArgumentException("Operator unknown: " + c);

Categories