I need help in converting an If-case into a switch statement and I'm working on enums.
An example of my enum is as below :
private enum FruitsType{
Apple("Apple"), Orange("Orange"), Mango("Mango"); }
And my method which contains If and Else-if Statements is as follows :
private String getFruitsPrefMsg() {
String message = getMessage();
if (message == null) {
message = getOtherMessage(); }
if(FruitsType.Apple.toString()) {
//return something; }
else if(FruitsType.Orange.toString()) {
// return something; }
else if(FruitsType.Mango.toString()) {
// return something; }
}
Not considering the logic in the code as this is just an example of my code, Can someone please help me to convert this aforementioned if and else-if statements(including the check for null) into a simple switch case, I would need the most simplest code possible using swtich. I want to use switch here as this is the criteria and I have to use switch statement.
I don't understand your conditions, you are not using the obtained message at all.
I would make the enum as follows:
private enum FruitsType {
Apple,
Orange,
Mango
}
As for the switch block, I would probably do something like:
private String getFruitsPrefMsg() {
String message = getMessage();
if(message == null)
message = getOtherMessage();
try {
switch(FruitsType.valueOf(message)) {
case Apple:
//return something
case Orange:
//return something
case Mango:
//return something
}
} catch(IllegalArgumentException exception) {
//Message is not in the enum.
//Handle error
//You can return something here
}
//Or return something here
}
I know the try-catch block is pretty ugly, but that's the easiest solution i'm able to think of.
Good luck with that.
Related
I have a String ("AA,BB,CC") and user select "AA" and "BB" from the jsp.
Now can i get the both the values Since, i have added if condition here
Code:
String UserSeclected="AA,BB,CC";
if(userSelectedValues.contains("AA")) {
//some code here
}else if(userSelectedValues.contains("BB")) {
//some code here
}else if(userSelectedValues.contains("CC")) {
//some code here
}
Because of if else condition I am getting single value. So, how to get the both the values AA and BB when user select?
Just do:
if(userSelectedValues.contains("AA")) {
//some code here
}
if(userSelectedValues.contains("BB")) {
//some code here
}
if(userSelectedValues.contains("CC")) {
//some code here
}
Since else-if statements break if one condition returns true.
String UserSeclected="AA,BB,CC";
if(userSelectedValues.contains("AA")) {
//some code here
}
if(userSelectedValues.contains("BB")) {
//some code here
}
if(userSelectedValues.contains("CC")) {
//some code here
}
Why use the else you need to check them all?
Try to avoid if...else
When the logic gets extended to check on various conditions, it becomes difficult to remember what condition we were checking or validating.
One of the good and recommended solutions is to have
public returnType someMethod(){
if(conditionA){ // do some operation; return; }
if(conditionB){ // do some operation; return; }
if(conditionC){ // do some operation; return; }
...................
...................
return default_values;
}
Hope this helps.
I'll give you some sample code. By simple modification you can achieve your requirement.
String UserSeclected="AA,BB,CC";
String[]arr=UserSeclected.split(",");
int length=arr.length;
for(int i=0;i<length;i++)
{
System.out.println(arr[i]);
}
I have one query that is I have used a method but there is many time I have used If Else ..not it become very ambiguous please advise can I use some other conditional loop also..below is my code..
if (cardType == AARP_CARD_TYPE) {
userResponse = messageBox.showMessage("CandidateAARPCardAttachCardToExistingTransaction",
null, IMessageBox.YESNO); // MSG:31.59
transaction.setValue(ITransactionHashtableWag.LOYALTY_MESSAGE_DISPLAYED,
WalgreensRewardsConstants.ATTACH_CANDIDATE_AARP_CARD);
} else if ((cardType == PSC_CARD_TYPE) && ((!PosHelper.isRunningAsService()))) {
userResponse = messageBox.showMessage("PendingPSCCardAttachCardToExistingTransaction", null,
IMessageBox.YESNO); // MSG:31.60
transaction.setValue(ITransactionHashtableWag.LOYALTY_MESSAGE_DISPLAYED,
WalgreensRewardsConstants.ATTACH_PENDING_PSC_CARD);
} else if ((cardType == DR_CARD_TYPE) && ((!PosHelper.isRunningAsService()))) {
userResponse = messageBox.showMessage("PendingDRCardAttachCardToExistingTransaction", null,
IMessageBox.YESNO); // MSG:31.63
transaction.setValue(ITransactionHashtableWag.LOYALTY_MESSAGE_DISPLAYED,
WalgreensRewardsConstants.ATTACH_PENDING_DR_CARD);
} else if ((cardType == WAG_LOYALTY_CARD_TYPE)){
transaction.setValue(ITransactionHashtableWag.LOYALTY_MESSAGE_DISPLAYED,
WalgreensRewardsConstants.ATTACH_NOT_ON_FILE);
if((!PosHelper.isRunningAsService())) {
userResponse = messageBox.showMessage("CardNotOnFileToAttach", null, IMessageBox.YESNO); // MSG:31.32
// BUC
// 1.22.1
}
} else { // If the device is neither of these, POS displays Message 1
// Button, MSG 31.14. [BUC
// 1.23.2]
displayMessage("InvalidLoyaltyCard");
transaction.setValue(ITransactionHashtableWag.LOYALTY_MESSAGE_DISPLAYED,
NOT_VALID_LOYALTY_CARD);
userResponse = -1;
}
Please advise how can I improve my above logic with some other conditional statements as there is lots n lots of If Else is used..!!
If cardType is an enum, you can add methods to your enum, (say getName, getWag etc.) and call it:
userResponse = messageBox.showMessage(cardType.getMessage(), ...
transaction.setValue(cardType.getWag(), cardType.getRewards());
If it is an int or another non-enum type, you can use a switch as already proposed, or consider switching (haha) to an enum. You could also make PosHelper.isRunningAsService() a boolean parameter to those methods and all your if/else code would be reduced to 3 or 4 lines it seems (although it will introduce some coupling but you seem to have a lot of it already).
Your enum could look like this (simple example that you can complicate as required):
public enum CardType {
AARP_CARD_TYPE {
public String getName() {
return "CandidateAARPCardAttachCardToExistingTransaction";
}
},
PSC_CARD_TYPE {
public String getName() {
return "PendingPSCCardAttachCardToExistingTransaction";
}
};
public abstract String getName();
}
Or more compact, if you don't require complicated logic in the methods:
public static enum CardType {
AARP_CARD_TYPE("CandidateAARPCardAttachCardToExistingTransaction"),
PSC_CARD_TYPE ("PendingPSCCardAttachCardToExistingTransaction");
private final String transactionName;
CardType(String transactionName) {
this.transactionName = transactionName;
}
public String getName() {
return transactionName;
}
}
Use a switch statement instead.
switch (cardType) {
case AARP_CARD_TYPE:
// blah
break;
case PSC_CARD_TYPE:
// blah
break;
// ...
default:
// default blah
break;
}
You have some options: Pattern Strategy, Polymorphism or Events to avoid too much ifs/else
In your example probably the business logic is close to the user interface. You can use the MVC concept to separate the logic from the presentation and reduce the if/elses (if possible).
If you don't like adding methods to CardType as assylias suggested, you can create an 'Action' enum and add the method(s) to that one and use a Map
I have the below piece of code that I have developed ..
public byte determineCardType(final IInput inputData) {
byte cardType = UNKNOWN_CARD;
try {
if (isWagRewardsLoyaltyCard(inputData))
cardType = WAG_LOYALTY_CARD_TYPE;
else if (isDRCard(inputData)) //checking that card scanned and swiped is a DR Card
cardType = DR_CARD_TYPE;
else if (isWagRewardsPartnerCard(inputData))
cardType = AARP_CARD_TYPE;
return cardType;
} catch (Exception e) {
return UNKNOWN_CARD;
}
}
please advise me can the above code can be adjusted in switch loop, if yes then please advise, Thanks in advance.
the other code that is linked to it...
if((aarpCardSupport.isAARPCard(input))||(determineCardType(input)==DR_CARD_TYPE)) {
return true;
} else if((isDRCard(input))&&(isDRLoayltyEnabled())) { //would return 1 for DR card only when isDRLoayltyEnabled returns true
return true;
}
return false ;
Switch won't help you, but conditional expressions can:
return isWagRewardsLoyaltyCard(inputData) ? WAG_LOYALTY_CARD_TYPE
: isDRCard(inputData) ? DR_CARD_TYPE
: isWagRewardsPartnerCard(inputData) ? AARP_CARD_TYPE
: UNKNOWN_CARD;
I would strongly recommend against catching Exception, btw. Catch specific exception types if you must - although in that case I'd at least log the error before returning.
EDIT: As for the second piece of code, it looks like you just want:
return aarpCardSupport.isAARPCard(input)
|| determineCardType(input) == DR_CARD_TYPE
|| (isDRCard(input) && isDRLoayltyEnabled);
Although why determineCardType(input) would return something other than DR_CARD_TYPE when isDRCard(input) returns true is a mystery...
Don't do it. If you must do it, you could do it like this:
public byte determineCardType (final IInput inputData) {
byte cardType = UNKNOWN_CARD;
try {
switch (isWagRewardsLoyaltyCard (inputData) ? 1 :
(isDRCard (inputData) ? 2 : (isWagRewardsPartnerCard (inputData) ? 3 : 4)))
{
case 1: cardType = WAG_LOYALTY_CARD_TYPE; break;
case 2: cardType = DR_CARD_TYPE; break;
case 3: cardType = AARP_CARD_TYPE; break;
default: // UNKNOWN_CARD already default
}
return cardType;
} catch (CardException ce) {
return UNKNOWN_CARD;
}
}
}
But since you return a cardType as byte, you can switch later, after setting the type. This code is harder to read than your code. Jons code is at least lean.
I see you're new to switch statements. So I elaborate a little.
A switch statement is useful if your input is in Integral form (int, byte, short, Enum), and if you can match it against a - mostly medium short list of values.
And if you otherwise would use a sequence of if/else statements. Case statements needn't be mutual exclusive, but most times they are.
In your case, you call 3 methods which return booleans, so the input isn't integral. But your output is.
Later in the code, you could write:
byte cardType = determineCardType (inputDate);
switch (cardType)
{
case WAG_LOYALTY_CARD_TYPE: doWlct (foo, bar); break;
case DR_CARD_TYPE: doDct (); break;
case AARP_CARD_TYPE: doAct (baz); foobar (); break;
case UNKNOWN_CARD: System.err.println ("Unknown card");
}
Else you would have to write:
if (cardType == WAG_LOYALTY_CARD_TYPE)
doWlct (foo, bar);
else if (cardType == DR_CARD_TYPE)
doDct ();
else if (cardType == AARP_CARD_TYPE) {
doAct (baz);
foobar ();
}
else ...
Since Java 1.7 switch over Strings is possible as well, but until then, you could only switch over integral types, and the case labels have to be literally constant and known at compile time.
In OOP, switch statements are often abandoned in favor of dynamic dispatch.
interface Card {
public abstract int authenticate ();
}
class WagLoyalityCard implements Card {
public int authenticate () {
doWlct (foo, bar);
}
}
class DrCard implements Card {
public int authenticate () {
doDct ();
}
}
// ... and so on
Card card = new DrCard ();
// authenticate:
card.authenticate ();
// depending on the card type, DrCard.authenticate () or
// WagCard.authenticate () gets called.
I have read a lot of topics about code refactoring and avoiding of if else statements. Actually, I have a class where I am using a lot of if - else conditions.
More details: I am using the pull parser and on each line of my soap response, I will check if there is a tag I am interested on, if not, check another tag etc:
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
if (soapResponse.equals("EditorialOffice")){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialOffice += xpp.getText();
}
}
else if (soapResponse.equals("EditorialBoard")){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialBoard += xpp.getText();
}
}
else if (soapResponse.equals("AdvisoryBoard")){
eventType = xpp.next();
if (xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
}
}
eventType = xpp.next();
}
Now, I would like to use something else, instead of those if else conditions, but I don't know what.
Can you please give me an example?
Try to look at the strategy pattern.
Make an interface class for handling the responses (IMyResponse)
Use this IMyResponse to create AdvisoryBoardResponse, EditorialBoardResponse classes
Create an dictionary with the soapresponse value as key and your strategy as value
Then you can use the methods of the IMyResponse class by getting it from the dictionary
Little Example:
// Interface
public interface IResponseHandler {
public void handleResponse(XmlPullParser xxp);
}
// Concrete class for EditorialOffice response
private class EditorialOfficeHandler implements IResponseHandler {
public void handleResponse(XmlPullParser xxp) {
// Do something to handle Editorial Office response
}
}
// Concrete class for EditorialBoard response
private class EditorialBoardHandler implements IResponseHandler {
public void handleResponse(XmlPullParser xxp) {
// Do something to handle Editorial Board response
}
}
On a place you need to create the handlers:
Map<String, IResponseHandler> strategyHandlers = new HashMap<String,IResponseHandler>();
strategyHandlers.put("EditorialOffice", new EditorialOfficeHandler());
strategyHandlers.put("EditorialBoard", new EditorialBoardHandler());
Where you received the response:
IResponseHandler responseHandler = strategyHandlers.get(soapResponse);
responseHandler.handleResponse(xxp);
In this particular case, since the code is essentially identical for all 3 case except for the String being appended to, I would have a map entry for each of the Strings being built:
Map<String,String> map = new HashMap<String,String>();
map.put("EditorialOffice","");
map.put("EditorialBoard","");
map.put("AdvisoryBoard","");
// could make constants for above Strings, or even an enum
and then change your code to the following
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
String current = map.get(soapResponse);
if (current != null && xpp.getText()!=null) {
map.put( soapResponse, current += xpp.getText());
}
eventType = xpp.next();
}
No "if... then... else". Not even the added complexity of multiple classes for strategy patterns, etc. Maps are your friend. Strategy is great in some situations, but this one is simple enough to be solved without.
In Java 7 you can SWITCH on Strings. You could use that if you could use that ;-)
Besides zzzzzzz(etc.)'s comment... keep in mind that you are using XmlPullParser which makes you write ugly code like the one you have. You could register some callbacks that would split your code and make it 'better', but if possible, just use SimpleXML library or similar.
Also, you can refactor your code to make it more readable and less verbose. For instance, why do you call xpp.next() inside each if statement? Why not just calling it outside just once:
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
if (soapResponse.equals("EditorialOffice") && xpp.getText()!=null){
editorialOffice += xpp.getText();
}
else if (soapResponse.equals("EditorialBoard") && xpp.getText()!=null){
editorialBoard += xpp.getText();
}
else if (soapResponse.equals("AdvisoryBoard") && xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
}
eventType = xpp.next();
You could create a ResponseHandler interface with three implementations, one for each branch of your if/else construct.
Then have either a map mapping the different soapResponses to a handler, or a list with all the handler if it can handle that soapResponse.
You also should be able to move some of the boilerplate code to a common possibly abstract implementation of the response handler class.
As so often there a many variations of this. By utilizing the code duplication one actually needs only one implementation:
class ResponseHandler{
String stringToBuild = "" // or what ever you need
private final String matchString
ResponseHandler(String aMatchString){
matchString = aMatchString
}
void handle(XppsType xpp){
if (xpp.getName().toString().equals(matchString){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialOffice += xpp.getText();
}
}
}
}
Your code becomes
List<ResponseHandler> handlers = Arrays.asList(
new ResponseHandler("EditorialOffice"),
new ResponseHandler("EditorialBoard"),
new ResponseHandler("AdvisoryBoard"));
if(eventType == XmlPullParser.START_TAG) {
for(ResponseHandler h : handlers)
h.handle(xpp);
}
vast question that is this one and there is no real answer. (and I don't use soap very often)
here a just some ideas based on your code:
first you can groupe duplicate code
if (soapResponse.equals("EditorialOffice")
||soapResponse.equals("EditorialBoard")
||soapResponse.equals("AdvisoryBoard")){
Another good thing you can do is play around with switch staments like:
switch(soapResponse){
case "EditorialOffice":
case "EditorialBoard":
case "AdvisoryBoard":
eventType = xpp.next();
if (xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
break;
Also you should consider breaking down you test into small functions:
public bool interestingTag(string s){
return (soapResponse.equals("EditorialOffice")
||soapResponse.equals("EditorialBoard")
||soapResponse.equals("AdvisoryBoard"));
}
public processData(xpp){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialBoard += xpp.getText();
}
....}
So that you can just process all your answers in a while loop and you super long if else becomes a 5~10 line function
But as I said there are so many good ways of doing the same thing
You haven't mentioned if you can or do use Java 7. As of that java version you can use Strings in switch statements.
Other than that, encapsulating the logic for each case is a good idea, for example:
Map<String, Department> strategyMap = new HashMap<String, Department>();
strategyMap.put("EditorialOffice", new EditorialOfficeDepartment());
strategyMap.put("EditorialBoard", new EditorialBoardDepartment());
strategyMap.put("AdvisoryBoard", new AdvisoryBoardDepartment());
Then you can simply select the correct strategy from the Map and use it:
String soapResponse = xpp.getName();
Department department = strategyMap.get(soapResponse);
department.addText(xpp.getText());
Department is of course in interface...
You can define an enum like the following:
public enum SoapResponseType {
EditorialOffice(1, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
},
EditorialBoard(2, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
},
AdvisoryBoard(3, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
};
public static SoapResponseType nameOf(String name) {
for (SoapResponseType type : values()) {
if (type.getName().equalsIgnoreCase(name)) {
return type;
}
}
return null;
}
public void handle(XmlPullParser xpp) {
return null;
}
}
Use above enum like this:
SoapResponseType type = SoapResponseType.nameOf("input string");
if (type != null) {
type.handle(xpp);
}
It's clean code, isn't it!
I have a history in programming, but not much in software development. I'm currently writing a piece of software for the company I work at, and I've come to challenge myself on the readability of my code.
I want to know whether this is a "valid" alternative to embedded if statements, or if there is anything better I could use.
Let's say I have the following method:
public void someMethod()
{
if (some condition)
{
if (some condition 2)
{
if (some condition 3)
{
// ...etc all the way until:
doSomething();
}
else
{
System.err.println("Specific Condition 3 Error");
}
}
else
{
System.err.println("Specific Condition 2 Error");
}
}
else
{
System.err.println("Specific Condition 1 Error");
}
}
Now the first thing I should point out is that in this instance, combining the conditions (with &&) isn't possible, since each one has a unique error that I want to report, and if I combined them I wouldn't be able to do that (or would I?). The second thing I should point out before anyone screams "SWITCH STATEMENT!" at me is that not all of these conditions can be handled by a switch statement; some are Object specific method calls, some are integer comparisons, etc.
That said, is the following a valid way of making the above code more readable, or is there a better way of doing it?
public void someMethod()
{
if (!some condition)
{
System.err.println("Specific Condition 1 Error");
return;
}
if (!some condition 2)
{
System.err.println("Specific Condition 2 Error");
return;
}
if (!some condition 3)
{
System.err.println("Specific Condition 3 Error");
return;
}
doSomething();
}
So basically, instead of checking for conditions and reporting errors in else blocks, we check for the inverse of the condition and return if it is true. The result should be the same, but is there a better way of handling this?
If I was being particularly pedantic I would use something like this.
boolean c1, c2, c3;
public void someMethod() {
boolean ok = true;
String err = "";
if (ok && !(ok &= c1)) {
err = "Specific Condition 1 Error";
}
if (ok && !(ok &= c2)) {
err = "Specific Condition 2 Error";
}
if (ok && !(ok &= c3)) {
err = "Specific Condition 3 Error";
}
if ( ok ) {
doSomething();
} else {
System.out.print(err);
}
}
You are now single-exit AND flat.
Added
If &= is difficult for you, use something like:
if (ok && !c3) {
err = "Specific Condition 3 Error";
ok = false;
}
I would write it as
if (failing condition) {
System.err.println("Specific Condition 1 Error");
} else {
somethingExpensiveCondition2and3Dependon();
if (failing condition 2)
System.err.println("Specific Condition 2 Error");
else if (failing condition 3)
System.err.println("Specific Condition 3 Error");
else
doSomething();
}
yes, your code in both cases smells of conditional complexity (code smells)
Java is an OOP language, so your code should be factored to in the spirit of OOD, something like this:
for (Condition cond : conditions) {
if (cond.happens(params))
cond.getHandler().handle(params);
}
conditions list should be injected to this class, this way when a new condition is added or removed the class doesn't change. (open close principle)
Your second approach is fairly good. If you want something a little more baroque, you can move your conditions into Callable objects. Each object can also be provided with a way of handling errors. This lets you write an arbitrarily long series of tests without sacrificing functionality.
class Test {
private final Callable<Boolean> test;
private final Runnable errorHandler;
public Test(Callable<Boolean> test, Runnable handler) {
this.test = test;
errorHandler = handler;
}
public boolean runTest() {
if (test.call()) {
return true;
}
errorHandler.run();
return false;
}
}
You could then organize your code as follows:
ArrayList<Test> tests;
public void someMethod() {
for (Test test : tests) {
if (!test.runTest()) {
return;
}
}
doSomething();
}
EDIT
Here's a more general version of the above. It should handle almost any case of this type.
public class Condition {
private final Callable<Boolean> test;
private final Runnable passHandler;
private final Runnable failHandler;
public Condition(Callable<Boolean> test,
Runnable passHandler, Runnable failHandler)
{
this.test = test;
this.passHandler = passHandler;
this.failHandler = failHandler;
}
public boolean check() {
if (test.call()) {
if (passHandler != null) {
passHandler.run();
}
return true;
}
if (errorHandler != null) {
errorHandler.run();
}
return false;
}
}
public class ConditionalAction {
private final ArrayList<Condition> conditions;
private final Runnable action;
public ConditionalAction(ArrayList<Condition> conditions,
Runnable action)
{
this.conditions = conditions;
this.action = action;
}
public boolean attemptAction() {
for (Condition condition : conditions) {
if (!condition.check()) {
return false;
}
}
action.run();
return true;
}
}
One might be tempted to add some sort of generic data that could be passed around to share info or collect results. Rather than doing that, I'd recommend implementing such data sharing within the objects that implement the conditions and action, and leave this structure as is.
For this case, that's about as clean as you are going to get it, since you have both custom criteria and custom responses to each condition.
What you are in essence doing is validating some conditions before calling the doSomething() method. I would extract the validation into a separate method.
public void someMethod() {
if (isValid()) {
doSomething();
}
}
private boolean isValid() {
if (!condition1) {
System.err.println("Specific Condition 1 Error");
return false;
}
if (!condition2) {
System.err.println("Specific Condition 2 Error");
return false;
}
if (!condition3) {
System.err.println("Specific Condition 3 Error");
return false;
}
return true;
}
Nope, that's about what you get in Java. If you have too many of these, it may indicate that you should refactor a bit, and possibly even rethink your algorithm -- it may be worthwhile trying to simplify it a bit, because otherwise you're going to come back to the code in a few months and wonder why the heck a + b + c + d = e but a + b' + c + d = zebra
The second option you have is the more readable one. While multiple returns are usually not recommended putting all of them at the beginning of the code is clear (it isn't as if they are scattered all over the method). Nested ifs on the other hand, are hard to follow and understand.