I find the PowerScript's CHOOSE CASE statement very useful, as it make so that the code is more clearly than a lot of ifs and else ifs.
Here a example of how it works, from the above link:
CHOOSE CASE weight
CASE IS < 16
Postage=Weight*0.30
Method="USPS"
CASE 16 to 48
Postage=4.50
Method="UPS"
CASE ELSE
Postage=25.00
Method="FedEx"
END CHOOSE
a CASE 5 to 11 is the same as CASE 5, 6, 7, 8, 9, 10, 11
Note that the CHOOSE CASE is not equivalent to java's switch
In Java, you can use multiple case statements, but there isn't a nice way to specify an expression as the case qualifier, just literals:
switch(weight) {
case 1:
case 2:
case 3:
postage = weight * 0.30;
method = "USPS";
break;
case 4:
case 5:
case 6:
postage = 4.5;
method = "UPS";
break;
default:
postage = 25.0;
method = "FedEx";
break;
}
To get nice ranges, stick with if/else:
if(weight > 0 && weight <= 3) {
postage = weight * 0.30;
method = "USPS";
}
else if(weight > 3 && weight <= 6) {
postage = 4.5;
method = "UPS";
}
else {
postage = 25.0;
method = "FedEx";
}
If your objective is cleaning up the decision point, you could encapsulate the code that decides what case applies separately from the code that uses that decision, as in:
enum WeightClass { LOW, MEDIUM, HIGH };
public WeightClass determineWeightClass(int weight)
{
return (weight < 16)
? WeightClass.LOW
: (weight <= 48
? WeightClass.MEDIUM
: WeightClass.HIGH);
}
And at the decision point:
switch(determineWeightClass(weight))
{
case LOW:
...
break;
case MEDIUM:
...
break;
case HIGH:
...
break;
}
Not exactly the same. If you want to implement such fragment in Java, you have to use if-else[-if] statement.
Basically, it should look like this:
if (weight < 16) {
//something
} else if (weight >= 16 && weight <= 48) {
//something else
} else {
//some other thing
}
Hope it works for you. :)
If there are only 3 cases, a series of if/else is fine. If you have many conditions, you could use a Navigable map and couple it with an enum for a nice and slick design:
public class Test1 {
public static void main(String[] args) {
printDelivery(0);
printDelivery(5);
printDelivery(16);
printDelivery(48);
printDelivery(50);
}
private static void printDelivery(int weight) {
Delivery d = Delivery.getDelivery(weight);
System.out.println("Weight: " + weight + " => $" + d.getPostage(weight) + " with " + d.getMethod());
}
static enum Delivery {
LOW_WEIGHT(15) {
public double getPostage(int weight) { return 0.3 * weight; }
public String getMethod() { return "USPS"; }
}, MEDIUM_WEIGHT(47) {
public double getPostage(int weight) { return 4.5; }
public String getMethod() { return "UPS"; }
}, HIGH_WEIGHT(Integer.MAX_VALUE){
public double getPostage(int weight) { return 25.0; }
public String getMethod() { return "FedEx"; }
};
private static final NavigableMap<Integer, Delivery> deliveries = new TreeMap<> ();
static {
for (Delivery e : values()) {
deliveries.put(e.maxWeight, e);
}
}
private final int maxWeight;
Delivery(int maxWeight) {
this.maxWeight = maxWeight;
}
public static Delivery getDelivery(int weight) {
return deliveries.ceilingEntry(weight).getValue();
}
abstract double getPostage(int weight);
abstract String getMethod();
}
}
No. You would have to use a series of if-elseif-else statements.
Related
I am a beginner to Java and I have a health insurance program, which returns a total quote based on if the customer has any health conditions already present or not. Each health condition increases the total amount by a different %, and there can be more than one health condition present, in which case the total will be increased according to the order of the if statements. For example, the customer may have "Bone marrow", in which case the total is multiplied by 20%, or they may have "Bone marrow" and "Cancer" in which case the total is increased by 20% and then 25% in that order.
I have this written in multiple independent if statements because unlike with an if else statement, there can be more than one health condition present. Is there a way I can write this in a way that's more elegant than just a long list of if statements?
if (customer.getHealthConditions().equals("Bone Marrow")) {
total *= 1.2;
}
if (customer.getHealthConditions().equals("Cancer")) {
total *= 1.25;
}
if (customer.getHealthConditions().equals("Cardiovascular Disease")) {
total *= 1.3;
}
if (customer.getHealthConditions().equals("Gastrointestinal")) {
total *= 1.1;
}
if (customer.getHealthConditions().equals("Infections")) {
total *= 1.1;
}
if (customer.getHealthConditions().equals("Kidneys")) {
total *= 1.25;
}
if (customer.getHealthConditions().equals("Lungs")) {
total *= 1.25;
}
if (customer.getHealthConditions().equals("Musculoskeletal")) {
total *= 1.3;
}
It seems that switch statement is more appropriate in this case:
double quotient = 1.0;
switch(customer.getHealthConditions()) {
case "Bone Marrow":
quotient = 1.2; break;
case "Cancer":
case "Kidneys":
case "Lungs":
quotient = 1.25; break;
case "Cardiovascular Disease":
case "Musculoskeletal":
quotient = 1.3; break;
case "Gastrointestinal":
case "Infections":
quotient = 1.1; break;
}
total *= quotient;
In Java 12+ switch statement was enhanced with multiple cases and arrow -> so it may be written as:
total *= switch(customer.getHealthConditions()) {
case "Bone Marrow" -> 1.2;
case "Cancer", "Kidneys", "Lungs" -> 1.25;
case "Cardiovascular Disease", "Musculoskeletal" -> 1.3;
case "Gastrointestinal", "Infections" -> 1.1;
default -> 1.0;
}
Update
If health conditions are multiple, then equals is not applicable at all, instead String::contains or Collection::contains should be used and it would be better to have a map or enum of the disease to quotient:
Map<String, Double> quotients = Map.of(
"Bone Marrow", 1.2,
"Cancer", 1.25,
"Kidneys", 1.25,
"Lungs", 1.25
// ...
);
total *= quotients.entrySet().stream()
.filter(e -> customer.getHealthConditions().contains(e.getKey()))
.map(Map.Entry::getValue)
.reduce(1.0, (p, v) -> p * v);
I think here an enum could be useful, we need not only to sum all the values but also the order may be important (the progressive premium increase changes otherwise)
import java.util.Comparator;
import java.util.Optional;
import static java.util.Arrays.*;
enum HealthConditionPremium {
boneMarrow(1,1.2, "Bone Marrow"),
cancer(2,1.25, "Cancer"),
cardiovascularDisease(3,1.3, "Cardiovascular Disease"),
gastrointestinal(4,1.1, "Gastrointestinal"),
infections(5,1.1, "Infections"),
kidneys(6,1.25, "Kidneys"),
lungs(7,1.25, "Lungs"),
musculoskeletal(8,1.3, "Musculoskeletal");
public final int order;
public final double premiumIncrease;
public final String matchString;
HealthConditionPremium(int order, double premiumIncrease, String matchString) {
this.order = order;
this.premiumIncrease = premiumIncrease;
this.matchString = matchString;
}
static Optional<HealthConditionPremium> of(String condition) {
return stream(values()).filter(healthCondition -> healthCondition.matchString.equals(condition)).findAny();
}
public static double totalForHealthConditions(String ...conditions) {
return stream(conditions).
filter(condition -> condition != null && !condition.isEmpty()).
map(HealthConditionPremium::of).
filter(Optional::isPresent).
map(Optional::get).
sorted(Comparator.comparingInt(hc -> hc.order)).
map(healthConditionPremium -> healthConditionPremium.premiumIncrease).
reduce(1.0, (total, additionalPremium) -> total * additionalPremium);
}
}
class Scratch {
public static void main(String[] args) {
Customer customer = new Customer("Gastrointestinal");
double total = 1;
if (customer.getHealthConditions().equals("Bone Marrow")) {
total *= 1.2;
}
if (customer.getHealthConditions().equals("Cancer")) {
total *= 1.25;
}
if (customer.getHealthConditions().equals("Cardiovascular Disease")) {
total *= 1.3;
}
if (customer.getHealthConditions().equals("Gastrointestinal")) {
total *= 1.1;
}
if (customer.getHealthConditions().equals("Infections")) {
total *= 1.1;
}
if (customer.getHealthConditions().equals("Kidneys")) {
total *= 1.25;
}
if (customer.getHealthConditions().equals("Lungs")) {
total *= 1.25;
}
if (customer.getHealthConditions().equals("Musculoskeletal")) {
total *= 1.3;
}
System.out.println("total = " + total);
System.out.println("----------------------------------");
double totalWithEnum = HealthConditionPremium.totalForHealthConditions("Gastrointestinal");
System.out.println("totalWithEnum = " + totalWithEnum);
System.out.println("----------------------------------");
double totalManyWithEnum = HealthConditionPremium.totalForHealthConditions("Gastrointestinal", "Cancer", "Kidneys");
System.out.println("totalManyWithEnum = " + totalManyWithEnum);
double totalManyWithEnumDifferentOrder = HealthConditionPremium.totalForHealthConditions("Cancer", "Gastrointestinal", "Kidneys");
System.out.println("totalManyWithEnumDifferentOrder = " + totalManyWithEnumDifferentOrder);
}
static class Customer {
private final String condition;
Customer(String condition) {
this.condition = condition;
}
public String getHealthConditions() {
return condition;
}
}
}
Output
total = 1.1
----------------------------------
totalWithEnum = 1.1
----------------------------------
totalManyWithEnum = 1.71875
totalManyWithEnumDifferentOrder = 1.71875
Some words of advice :)
Using a Double for premium (Money related) calculation is not advised, use BigDecimal Instead
The Reason for order in the enum is to make the order explicit and NOT rely on ordinal (order of definition of enum)
This way the definition of Health Conditions and Their Premiums is gathered in one place for easy reading.
The Assumption (and probably a big one) customer.getHealthConditions() actually returns an array of Strings to pass to totalForHealthConditions
class bool {
public static void main(String arg[]) {
int n = 2;
boolean b = (n % 2 == 0);
System.out.print(b);
String s = String.valueOf(b);
switch (s) {
case true:
System.out.println("even");
break;
default:
System.out.println("odd");
break;
}
}
i am getting problm of incompetible type
plz help i have to print a number to be odd or even without loop.
You are getting incompatible types because you are attempting to use a boolean case label true when the switch expression is a String s. You don't even need the String; just use b itself. booleans aren't allowed as switch expressions, but you don't need a switch if all you have is a boolean. Just use an if statement.
The variable used in the case in a String however in each case you are using a boolean:
public static void main(final String arg[]) {
final int n = 2;
final boolean b = n % 2 == 0;
System.out.print(b);
System.out.println(b ? "even" : "odd");
}
You can't switch on a String value in Java 6 or below. What you want is
if (b) {
System.out.println("even");
} else {
System.out.println("odd");
}
String s=String.valueOf(b); is useless.
Also consider using more descriptive names for your variables. b gives no information about what this variable means in the code logic. isEven for example is a much better name, see how the code is more readable now:
if (isEven) {
System.out.println("even");
} else {
System.out.println("odd");
}
i want to do this without any if else and without any loop
Strange requirement... It just makes the code less readable and more bloated. Usually you want switch for when there are more than 2 possible values. Anyway:
final int result = n % 2;
switch (result) {
case 0:
System.out.println("even");
break;
default:
System.out.println("odd");
}
Not sure if I understand question correctly, and from your comments it looks like you do not want to use if/else or switch - you can opt for using a wrapper.
IntWrapper wrapper = new IntWrapper(n);
System.out.println("Is Even ? "+wrapper.isEven());
System.out.println("Is Odd ? "+wrapper.isOdd());
class IntWrapper
{
private int x;
public IntWrapper(int x)
{
this.x = x;
}
public boolen isEven()
{
return x%2==0;
}
public boolean isOdd()
{
return !isEven();
}
}
I'm trying to write a recursive function in Java, to determine how to finish for a game of Darts. Basically, you have a maximum of 3 darts, en you have to finish with a double.
If you don't know the rule of Darts x01 games with Double Out finishing, it's difficult to understand this question... Let me try to explain. For simplicity, I keep the Bull's eye out of the equation for now.
Rules:
1) You have three darts which you can throw at number 1 through 20
2) A single hit can have a single, double or triple score
E.g. you can hit:
single 20 = 20 points or
double 20 = 40 points or
triple 20 = 60 points
3) In one turn, you can score a maximum of 180 points (3x triple 20 = 3*60 = 180). Anything higher than 180 is impossible. This doesn't mean anything below 180 IS possible. 179 for example, is impossible as well, because the next best score is triple20+triple20+triple19 = 167
4) Normally, you start at 501, and you throw 3 darts, untill you have exactly 0 points left.
5) Now, in Double Out, it is required that the last dart hits a Double
E.g. if you have 180 points left, you cannot finish, because your last dart has to be a double. So the maximum (with ignoring the bulls eye) = triple20 + triple20 + double20 = 160
And if your score is 16, you can simply finish using 1 dart by hitting the double 8.
Another example, if your score is 61, you can hit triple17 + double5 (= 51 + 10)
Current Code
Anyway, below is what I have so far. I know it's far from what I need, but no matter what I try, i always get stuck. Perhaps someone can share his thoughts on an another approach
private class Score{
int number; // the actual number, can be 1...20
int amount; // multiplier, can be 1, 2 or 3
public Score(int number, int amount){
this.number = number; // the actual number, can be 1...20
this.amount = amount; // multiplier, can be 1, 2 or 3
}
public int value()
{
return number * amount; // the actual score
}
public void increment()
{
if(this.amount == 0)
this.amount = 1;
this.number++;
if(this.number >= 20)
{
this.number = 0;
this.amount++;
if(this.amount >= 3)
this.amount = 3;
}
}
}
public ArrayList<Score> canFinish(int desired, ArrayList<Score> score){
// If this is the case -> we have bingo
if(eval(score) == desired) return score;
// this is impossible -> return null
if(eval(score) > 170) return null;
// I can't figure out this part!!
Score dart3 = score.remove(2);
Score dart2 = score.remove(1);
if(dart2.eval() < 60){
dart2.increment();
}
else if(dart3.eval() < 60){
dart3.increment();
}
score.add(dart2);
score.add(dart3);
return canFinish(desired, score);
}
public int eval(ArrayList<Score> scores)
{
int total = 0;
for(Score score : scores){
total += score.value();
}
return total;
}
I want to simply call:
ArrayList<Score> dartsNeeded = new ArrayList<Score>();
dartsNeeded.add(new Score(16, 2)); // Add my favourite double
dartsNeeded.add(new Score(0, 0));
dartsNeeded.add(new Score(0, 0));
// and call the function
dartsNeeded = canFinish(66, dartsNeeded);
// In this example the returned values would be:
// [[16,2],[17,2],[0,0]] -> 2*16 + 2*17 + 0*0 = 66
// So I can finish, by throwing Double 17 + Double 16
So, if it is impossible to finish, the function would return null, but if there is any possible finish, i reveive that ArrayList with the 3 darts that I need to make my desired score...
Short Summary
The problem is that the above code only helps to find 1 dart, but not for the combination of the two darts. So canFinish(66, darts) works -> but canFinish(120, darts) gives a StackOverflow Exception. For 120, I would expect to get somthing like triple20, double14, double16 or any other valid combination for that matter.
If you log the scores that canFinish tries, you can see that there are a lot of possibilities missed out. Values of 20 are ignored, and one dart is incremented completely before the other dart values are modified.
Instead, it can be solved recursively as follows. canFinish(desired, score) returns any combination of darts that can be added to score to give the total of desired. Call it with a list of however many darts you know, or any empty list to find any possibility.
canFinish(desired, score)
if darts sum to desired, return desired
if there are fewer than 3 darts in score
for each possible value of a dart (if it's the last dart, check for a double)
add dart to score
if canFinish(desired, score) != null
return canFinish(desired, score)
end
remove dart from score
end
end
return null
end
I ended up using the following functions. Which kind of is a combination of switch statments and recursion... Hope someone finds it as usefull as I
public static void getCheckout(int score, int fav_double, ICheckOutEvent listener)
{
if(score > 170) return;
if(score == 170) listener.onCheckOut("T20 T20 Bull");
ArrayList<Dart> darts = new ArrayList<Dart>();
darts.add(new Dart(fav_double, 2));
darts.add(new Dart(0,0));
darts.add(new Dart(0,0));
darts = getDarts(score, darts);
if(darts != null) {
listener.onCheckOut(toString(darts));
return;
}
for(int dubble = 20 ; dubble >= 1 ; dubble--)
{
if(dubble == fav_double) continue;
darts = new ArrayList<Dart>();
darts.add(new Dart(dubble, 2));
darts.add(new Dart(0,0));
darts.add(new Dart(0,0));
darts = getDarts(score, darts);
if(darts != null){
listener.onCheckOut(toString(darts));
return;
}
}
}
public static ArrayList<Dart> getDarts(int desired, ArrayList<Dart> score)
{
Dart dart1 = canFinish(desired);
if(dart1 != null){
score.set(0, dart1);
return score;
}
int rest = desired - score.get(0).value();
Dart dart2 = canScore(rest);
if(dart2 != null)
{
score.set(0, score.get(0));
score.set(1, dart2);
return score;
}
Dart temp = score.get(1);
if(temp.increment())
{
rest = desired - score.get(0).value() - temp.value();
score.set(0, score.get(0));
score.set(1, temp);
Dart dart3 = canScore(rest);
if(dart3 != null)
{
score.set(2, dart3);
return score;
}
if(rest > 60 && temp.increment())
temp.estimate(rest / 2);
score.set(1, temp);
return getDarts(desired, score);
}
return null;
}
public static int eval(ArrayList<Dart> scores)
{
int total = 0;
for(Dart score : scores){
total += score.value();
}
return total;
}
public static Dart canFinish(int points)
{
switch(points)
{
case 2: return new Dart(1, 2);
case 4: return new Dart(2, 2);
case 6: return new Dart(3, 2);
case 8: return new Dart(4, 2);
case 10: return new Dart(5, 2);
case 12: return new Dart(6, 2);
case 14: return new Dart(7, 2);
// etc. etc.
case 40: return new Dart(20, 2);
case 50: return new Dart(25, 2);
}
return null;
}
public static Dart canScore(int points)
{
switch(points)
{
case 1: return new Dart(1, 1);
case 2: return new Dart(2, 1);
case 3: return new Dart(3, 1);
// etc. etc.
case 20: return new Dart(20, 1);
case 21: return new Dart(7, 3);
case 22: return new Dart(11, 2);
//case 23: impossible
case 24: return new Dart(12, 2);
// etc. etc.
case 57: return new Dart(19, 3);
case 60: return new Dart(20, 3);
}
return null;
}
And for completeness, here's the Dart class I created as a helper
private static class Dart{
int number;
int amount;
public Dart(int number, int amount){
this.number = number;
this.amount = amount;
}
public int value()
{
return number * amount;
}
public void estimate(int estimate)
{
Dart temp = canScore(estimate);
if(temp != null){
this.amount = temp.amount;
this.number = temp.number;
} else{
this.number = estimate / 3;
if(number >= 19)
this.number = 19;
this.amount = 3;
}
}
public boolean increment()
{
if(this.amount == 3 && this.number == 20)
return false;
if(this.amount == 0)
this.amount = 1;
this.number++;
if(this.number >= 20)
{
this.number = 20;
this.amount++;
if(this.amount >= 3){
this.amount = 3;
}
}
return true;
}
public String toString()
{
return "["+number+","+amount+"]";
}
}
class RecursiveDartboard {
public Set<Out> outsFor(int target) {
HashSet<Out> outs = new HashSet<>();
for (Score doubleScore : doubles()) {
List<Score> scores = new ArrayList();
scores.add(doubleScore);
outs.addAll(recursiveOutsFor(target, scores)
.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList())
);
}
return outs;
}
private List<Optional<Out>> recursiveOutsFor(int target, List<Score> scores) {
List<Optional<Out>> outs = new ArrayList<>();
Out possibleOut = new Out(scores);
if (possibleOut.target() == target) {
outs.add(of(possibleOut));
} else if (scores.size() == 3) {
outs.add(empty());
} else {
for (Score score : allPossibleScores()) {
List<Score> nextScores = new ArrayList<>();
nextScores.addAll(scores);
nextScores.add(score);
outs.addAll(recursiveOutsFor(target, nextScores));
}
}
return outs;
}
}
public class A {
public void search(boolean[] searchList) {
// searchList array is used to identify what options to search for in a given order
// e.g. boolean [] searchList = new boolean [] {false, false, true, false};
boolean searchL = false;
boolean searchM = false;
boolean searchK = false;
boolean searchA = false;
if(searchList[0] == true) searchL = true;
if(searchList[1] == true) searchM = true;
if(searchList[2] == true) searchK = true;
if(searchList[3] == true) searchA = true;
if(searchL == true) // write a query to search for all Ls
if(searchM == true) // write a query to search for all Ms
...........
}
Is there a way I can simplify this code ?
#All : Sorry for posting a wrong question before. I was confused!
Thanks,
Sony
I am a big fan of enums:
public class A {
enum SearchType {
L, M, A, K;
}
public void search(SearchType type) {
switch (type) {
case L:
System.out.println("Searching for L");
break;
case M:
System.out.println("Searching for M");
break;
case A:
System.out.println("Searching for A");
break;
case K:
System.out.println("Searching for K");
break;
default:
System.out.println("what to do here?");
// throw exception?
}
note also: your scenario allowed more than one search boolean to be true at a time, I assumed that was not your goal, but if it is we can tweak this a bit.
You should convert your state into an enum. For example your search booleans seem to be exclusive so i would do something like this:
enum SearchOption {
searchA, searchK, searchL, searchM
}
// then you can do
SearchOption searchOption = searchA;
switch (searchOption) {
case searchA:
System.out.println("I am searching for A");
break;
case searchK:
System.out.println("I am searching for K");
break;
case searchL:
System.out.println("I am searching for L");
break;
case searchM:
System.out.println("I am searching for M");
break;
}
If your states aren't exclusive you should try build to build a super set of exclusive states initially.
Why don't employ OOP? Like:
public interface Seeker {
void seek();
}
public class LSeeker implements Seeker {
void seek() { System.out.println("Will search for L"); }
}
// ... More implementations of Seeker
public class SeekDriver {
void seek(Seeker seeker) { seeker.seek(); }
}
public class A {
public enum SearchOption {
SEARCH_L,
SEARCH_M,
SEARCH_A,
SEARCH_K;
}
/**
* Make them pass in an enum for your search.
* Pros: type safe, can only use the selections you give
* Cons: must add to the enum to add new types
* #param option
*/
public void enumSearch(SearchOption option) {
switch(option) {
case SEARCH_A:
System.out.println("I am searching for A");
break;
case SEARCH_K:
System.out.println("I am searching for K");
break;
case SEARCH_L:
System.out.println("I am searching for L");
break;
case SEARCH_M:
System.out.println("I am searching for M");
break;
}
}
/**
* Use a primitive for your input
* Pros: Gives you more options without updating the enum
* Cons: Users could enter input you don't really want them to use
* #param option
*/
public void charSearch(char option) {
switch(option) {
case 'a':
case 'A':
System.out.println("I am searching for A");
break;
case 'k':
case 'K':
System.out.println("I am searching for K");
break;
case 'l':
case 'L':
System.out.println("I am searching for L");
break;
case 'm':
case 'M':
System.out.println("I am searching for M");
break;
}
}
/**
* Use a primitive and don't even actually check it! Just run with it!
* #param option
*/
public void uncheckedSearch(char option) {
System.out.println("I am searching for " + option);
}
}
As per your comment, here's my updated example of that method - make sure the comment at the top is updated!
/**
* Perform the search based on the options provided
* The list should be in the order of L, M, A, K
* #note update this comment as more search options are added
* #param searchList the list of flags indicating what to search for
*/
public void search(boolean[] searchList) {
// as per docs, [0] denotes an L search:
if(searchList[0])
// write a query to search for all Ls
// as per docs, [1] denotes an M search:
if(searchList[1])
// write a query to search for all Ms
// as per docs, [2] denotes an A search:
if(searchList[2])
// write a query to search for all As
// as per docs, [3] denotes a K search:
if(searchList[3])
// write a query to search for all Ks
}
Latest idea:
// Use the SearchOption enum from above
Map<SearchOption, String> searches = new HashMap<SearchOption, String>();
public List<SearchResult> search(List<SearchOption> options) {
List<SearchResult> results = new LinkedList<SearchResult>();
for(SearchOption option : options) {
String query = searches.get(option);
SearchResult result = MySearchService.executeQuery(query);
results.add(result);
}
return results;
}
Like this: ?
public class A {
public void search() {
private static final int SEARCH_L = -1;
private static final int SEARCH_M = 0;
private static final int SEARCH_A = 1;
private static final int SEARCH_K = 2;
int status;
switch(status){
case SEARCH_L:
System.out.println("I am searching for L");
break;
case SEARCH_M:
System.out.println("I am searching for M");
break;
// Etc
default:
// Log error didn't hit a known status
break;
}
}
Just trying to figure out how to use many multiple cases for a Java switch statement. Here's an example of what I'm trying to do:
switch (variable)
{
case 5..100:
doSomething();
break;
}
versus having to do:
switch (variable)
{
case 5:
case 6:
etc.
case 100:
doSomething();
break;
}
Any ideas if this possible, or what a good alternative is?
The second option is completely fine. I'm not sure why a responder said it was not possible. This is fine, and I do this all the time:
switch (variable)
{
case 5:
case 6:
etc.
case 100:
doSomething();
break;
}
Sadly, it's not possible in Java. You'll have to resort to using if-else statements.
public class SwitchTest {
public static void main(String[] args){
for(int i = 0;i<10;i++){
switch(i){
case 1: case 2: case 3: case 4: //First case
System.out.println("First case");
break;
case 8: case 9: //Second case
System.out.println("Second case");
break;
default: //Default case
System.out.println("Default case");
break;
}
}
}
}
Out:
Default case
First case
First case
First case
First case
Default case
Default case
Default case
Second case
Second case
Src: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Maybe not as elegant as some previous answers, but if you want to achieve switch cases with few large ranges, just combine ranges to a single case beforehand:
// make a switch variable so as not to change the original value
int switchVariable = variable;
//combine range 1-100 to one single case in switch
if(1 <= variable && variable <=100)
switchVariable = 1;
switch (switchVariable)
{
case 0:
break;
case 1:
// range 1-100
doSomething();
break;
case 101:
doSomethingElse();
break;
etc.
}
One Object Oriented option to replace excessively large switch and if/else constructs is to use a Chain of Responsibility Pattern to model the decision making.
Chain of Responsibility Pattern
The chain of responsibility pattern
allows the separation of the source of
a request from deciding which of the
potentially large number of handlers
for the request should action it. The
class representing the chain role
channels the requests from the source
along the list of handlers until a
handler accepts the request and
actions it.
Here is an example implementation that is also Type Safe using Generics.
import java.util.ArrayList;
import java.util.List;
/**
* Generic enabled Object Oriented Switch/Case construct
* #param <T> type to switch on
*/
public class Switch<T extends Comparable<T>>
{
private final List<Case<T>> cases;
public Switch()
{
this.cases = new ArrayList<Case<T>>();
}
/**
* Register the Cases with the Switch
* #param c case to register
*/
public void register(final Case<T> c) { this.cases.add(c); }
/**
* Run the switch logic on some input
* #param type input to Switch on
*/
public void evaluate(final T type)
{
for (final Case<T> c : this.cases)
{
if (c.of(type)) { break; }
}
}
/**
* Generic Case condition
* #param <T> type to accept
*/
public static interface Case<T extends Comparable<T>>
{
public boolean of(final T type);
}
public static abstract class AbstractCase<T extends Comparable<T>> implements Case<T>
{
protected final boolean breakOnCompletion;
protected AbstractCase()
{
this(true);
}
protected AbstractCase(final boolean breakOnCompletion)
{
this.breakOnCompletion = breakOnCompletion;
}
}
/**
* Example of standard "equals" case condition
* #param <T> type to accept
*/
public static abstract class EqualsCase<T extends Comparable<T>> extends AbstractCase<T>
{
private final T type;
public EqualsCase(final T type)
{
super();
this.type = type;
}
public EqualsCase(final T type, final boolean breakOnCompletion)
{
super(breakOnCompletion);
this.type = type;
}
}
/**
* Concrete example of an advanced Case conditional to match a Range of values
* #param <T> type of input
*/
public static abstract class InRangeCase<T extends Comparable<T>> extends AbstractCase<T>
{
private final static int GREATER_THAN = 1;
private final static int EQUALS = 0;
private final static int LESS_THAN = -1;
protected final T start;
protected final T end;
public InRangeCase(final T start, final T end)
{
this.start = start;
this.end = end;
}
public InRangeCase(final T start, final T end, final boolean breakOnCompletion)
{
super(breakOnCompletion);
this.start = start;
this.end = end;
}
private boolean inRange(final T type)
{
return (type.compareTo(this.start) == EQUALS || type.compareTo(this.start) == GREATER_THAN) &&
(type.compareTo(this.end) == EQUALS || type.compareTo(this.end) == LESS_THAN);
}
}
/**
* Show how to apply a Chain of Responsibility Pattern to implement a Switch/Case construct
*
* #param args command line arguments aren't used in this example
*/
public static void main(final String[] args)
{
final Switch<Integer> integerSwitch = new Switch<Integer>();
final Case<Integer> case1 = new EqualsCase<Integer>(1)
{
#Override
public boolean of(final Integer type)
{
if (super.type.equals(type))
{
System.out.format("Case %d, break = %s\n", type, super.breakOnCompletion);
return super.breakOnCompletion;
}
else
{
return false;
}
}
};
integerSwitch.register(case1);
// more instances for each matching pattern, granted this will get verbose with lots of options but is just
// and example of how to do standard "switch/case" logic with this pattern.
integerSwitch.evaluate(0);
integerSwitch.evaluate(1);
integerSwitch.evaluate(2);
final Switch<Integer> inRangeCaseSwitch = new Switch<Integer>();
final Case<Integer> rangeCase = new InRangeCase<Integer>(5, 100)
{
#Override
public boolean of(final Integer type)
{
if (super.inRange(type))
{
System.out.format("Case %s is between %s and %s, break = %s\n", type, this.start, this.end, super.breakOnCompletion);
return super.breakOnCompletion;
}
else
{
return false;
}
}
};
inRangeCaseSwitch.register(rangeCase);
// run some examples
inRangeCaseSwitch.evaluate(0);
inRangeCaseSwitch.evaluate(10);
inRangeCaseSwitch.evaluate(200);
// combining both types of Case implementations
integerSwitch.register(rangeCase);
integerSwitch.evaluate(1);
integerSwitch.evaluate(10);
}
}
This is just a quick straw man that I whipped up in a few minutes, a more sophisticated implementation might allow for some kind of Command Pattern to be injected into the Case implementations instances to make it more of a call back IoC style.
Once nice thing about this approach is that Switch/Case statements are all about side affects, this encapsulates the side effects in Classes so they can be managed, and re-used better, it ends up being more like Pattern Matching in a Functional language and that isn't a bad thing.
I will post any updates or enhancements to this Gist on Github.
This is possible with switch enhancements in Java 14. Following is a fairly intuitive example of how the same can be achieved.
switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> System.out.println("this month has 31 days");
case 4, 6, 9 -> System.out.println("this month has 30 days");
case 2 -> System.out.println("February can have 28 or 29 days");
default -> System.out.println("invalid month");
}
According to this question, it's totally possible.
Just put all cases that contain the same logic together, and don't put break behind them.
switch (var) {
case (value1):
case (value2):
case (value3):
//the same logic that applies to value1, value2 and value3
break;
case (value4):
//another logic
break;
}
It's because case without break will jump to another case until break or return.
EDIT:
Replying the comment, if we really have 95 values with the same logic, but a way smaller number of cases with different logic, we can do:
switch (var) {
case (96):
case (97):
case (98):
case (99):
case (100):
//your logic, opposite to what you put in default.
break;
default:
//your logic for 1 to 95. we enter default if nothing above is met.
break;
}
If you need finer control, if-else is the choice.
JEP 354: Switch Expressions (Preview) in JDK-13 and JEP 361: Switch Expressions (Standard) in JDK-14 will extend the switch statement so it can be used as an expression.
Now you can:
directly assign variable from switch expression,
use new form of switch label (case L ->):
The code to the right of a "case L ->" switch label is restricted to be an expression, a block, or (for convenience) a throw statement.
use multiple constants per case, separated by commas,
and also there are no more value breaks:
To yield a value from a switch expression, the break with value statement is dropped in favor of a yield statement.
Switch expression example:
public class SwitchExpression {
public static void main(String[] args) {
int month = 9;
int year = 2018;
int numDays = switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> 31;
case 4, 6, 9, 11 -> 30;
case 2 -> {
if (java.time.Year.of(year).isLeap()) {
System.out.println("Wow! It's leap year!");
yield 29;
} else {
yield 28;
}
}
default -> {
System.out.println("Invalid month.");
yield 0;
}
};
System.out.println("Number of Days = " + numDays);
}
}
Basically:
if (variable >= 5 && variable <= 100)
{
doSomething();
}
If you really needed to use a switch, it would be because you need to do various things for certain ranges. In that case, yes, you're going to have messy code, because things are getting complex and only things which follow patterns are going to compress well.
The only reason for a switch is to save on typing the variable name if you're just testing for numeric switching values. You aren't going to switch on 100 things, and they aren't going to be all doing the same thing. That sounds more like an 'if' chunk.
From the last java-12 release multiple constants in the same case label is available in preview language feature
It is available in a JDK feature release to provoke developer feedback based on real world use; this may lead to it becoming permanent in a future Java SE Platform.
It looks like:
switch(variable) {
case 1 -> doSomething();
case 2, 3, 4 -> doSomethingElse();
};
See more JEP 325: Switch Expressions (Preview)
// Noncompliant Code Example
switch (i) {
case 1:
doFirstThing();
doSomething();
break;
case 2:
doSomethingDifferent();
break;
case 3: // Noncompliant; duplicates case 1's implementation
doFirstThing();
doSomething();
break;
default:
doTheRest();
}
if (a >= 0 && a < 10) {
doFirstThing();
doTheThing();
}
else if (a >= 10 && a < 20) {
doTheOtherThing();
}
else if (a >= 20 && a < 50) {
doFirstThing();
doTheThing(); // Noncompliant; duplicates first condition
}
else {
doTheRest();
}
//Compliant Solution
switch (i) {
case 1:
case 3:
doFirstThing();
doSomething();
break;
case 2:
doSomethingDifferent();
break;
default:
doTheRest();
}
if ((a >= 0 && a < 10) || (a >= 20 && a < 50)) {
doFirstThing();
doTheThing();
}
else if (a >= 10 && a < 20) {
doTheOtherThing();
}
else {
doTheRest();
}
It is possible to handle this using Vavr library
import static io.vavr.API.*;
import static io.vavr.Predicates.*;
Match(variable).of(
Case($(isIn(5, 6, ... , 100)), () -> doSomething()),
Case($(), () -> handleCatchAllCase())
);
This is of course only slight improvement since all cases still need to be listed explicitly. But it is easy to define custom predicate:
public static <T extends Comparable<T>> Predicate<T> isInRange(T lower, T upper) {
return x -> x.compareTo(lower) >= 0 && x.compareTo(upper) <= 0;
}
Match(variable).of(
Case($(isInRange(5, 100)), () -> doSomething()),
Case($(), () -> handleCatchAllCase())
);
Match is an expression so here it returns something like Runnable instance instead of invoking methods directly. After match is performed Runnable can be executed.
For further details please see official documentation.
One alternative instead of using hard-coded values could be using range mappings on the the switch statement instead:
private static final int RANGE_5_100 = 1;
private static final int RANGE_101_1000 = 2;
private static final int RANGE_1001_10000 = 3;
public boolean handleRanges(int n) {
int rangeCode = getRangeCode(n);
switch (rangeCode) {
case RANGE_5_100: // doSomething();
case RANGE_101_1000: // doSomething();
case RANGE_1001_10000: // doSomething();
default: // invalid range
}
}
private int getRangeCode(int n) {
if (n >= 5 && n <= 100) {
return RANGE_5_100;
} else if (n >= 101 && n <= 1000) {
return RANGE_101_1000;
} else if (n >= 1001 && n <= 10000) {
return RANGE_1001_10000;
}
return -1;
}
for alternative you can use as below:
if (variable >= 5 && variable <= 100) {
doSomething();
}
or the following code also works
switch (variable)
{
case 5:
case 6:
etc.
case 100:
doSomething();
break;
}
I found a solution to this problem... We can use multiple conditions in switch cases in java.. but it require multiple switch cases..
public class MultiCSwitchTest {
public static void main(String[] args) {
int i = 209;
int a = 0;
switch (a = (i>=1 && i<=100) ? 1 : a){
case 1:
System.out.println ("The Number is Between 1 to 100 ==> " + i);
break;
default:
switch (a = (i>100 && i<=200) ? 2 : a) {
case 2:
System.out.println("This Number is Between 101 to 200 ==> " + i);
break;
default:
switch (a = (i>200 && i<=300) ? 3 : a) {
case 3:
System.out.println("This Number is Between 201 to 300 ==> " + i);
break;
default:
// You can make as many conditions as you want;
break;
}
}
}
}
}