Is it possible to avoid code duplication in such cases? (Java code)
void f()
{
int r;
boolean condition = true;
while(condition)
{
// some code here (1)
r = check();
if(r == 0)
break ;
else if(r == 1)
return ;
else if(r == 2)
continue ;
else if(r == 3)
condition = false;
// some code here (2)
r = check();
if(r == 0)
break ;
else if(r == 1)
return ;
else if(r == 2)
continue ;
else if(r == 3)
condition = false;
// some code here (3)
}
// some code here (4)
}
int check()
{
// check a condition and return something
}
A possible solution may be using Exceptions, but that doesn't seem to be a good practice.
Is there any so-called good pattern of program flow control in such cases? For example, a way to call break ; from inside the check() function.
(Possibly in other programming languages)
Some good answers (especially #Garrett's just now) to a tough question but I'll add my $0.02 for posterity.
There is no easy answer here about how to refactor this block without seeing the actual code but my reaction to it is that it needs to be redesigned.
For example, a way to call break ; from inside the check() function. (Possibly in other programming languages)
If you are asking for a different break that Java does not support (without a hack) and having the duplicated check() and various different loop exit/repeat code indicates to me that this is a large and complicated method. Here are some ideas for you to think about:
Each of the some code here blocks are doing something. If you pull those out to their own methods, how does that change the loop?
Maybe break the loop down into a series of comments. Don't get deep into the code but think about it conceptually to see if a different configuration drops out.
Have you had another developer in your organization who is not involved with this code take a look at it? If you explain in detail how the code works someone they may see some patterns that you are not since you are in the weeds.
I also think that #aix's idea of a finite state machine is a good one but I've needed to use this sort of mechanism very few times in my programming journeys -- mostly during pattern recognition. I suspect that a redesign of the code with smaller code blocks pulled into methods will be enough to improve the code.
If you do want to implement the state machine here are some more details. You could have a loop that was only running a single switch statement that called methods. Each method would return the next value for the switch. This doesn't match your code completely but something like:
int state = 0;
WHILE: while(true) {
switch (state) {
case 0:
// 1st some code here
state = 1;
break;
case 1:
state = check();
break;
case 2:
return;
case 3:
break WHILE;
case 4:
// 2nd some code
state = 1;
break;
...
}
}
Hope some of this helps and best of luck.
The best way to avoid this duplication is not to let it happen in the first place by keeping your methods small and focused.
If the // some code here blocks are not independent, then you need to post all the code before someone can help you refactor it. If they are independent then there are ways to refactor it.
Code smell
First of all, I second aix's answer: rewrite your code! For this, the state design pattern might help. I would also say that using break, continue and return in such a way is just as much a code smell as the code duplication itself.
Having said that, here is a solution, just for fun
private int r;
void f()
{
distinction({void => codeBlock1()}, {void => codeBlock4()}, {void => f()},
{void => distinction( {void => codeBlock2()},{void => codeBlock4()},
{void => f()}, {void => codeBlock3()} )
});
}
void distinction( {void=>void} startingBlock, {void=>void} r0Block, {void=>void} r2Block, {void=>void} r3Block){
startingBlock.invoke();
r = check();
if(r == 0)
r0Block.invoke();
else if(r == 1)
{}
else if(r == 2)
r2Block.invoke();
else if(r == 3)
// if condition might be changed in some codeBlock, you still
// would need the variable condition and set it to false here.
r3Block.invoke();
}
This uses closures. Of course the parameters r0Block and r2Block could be ommited and instead codeBlock4() and f() hard-coded within distinction(). But then distinction() would only be usable by f(). With Java <=7, you would need to use an Interface with the method invoke() instead, with the 4 implementations codeBlock1 to codeBlock4. Of course this approach is not at all readable, but so general that it would work for any business logic within the codeBlocks and even any break/return/continue-orgy.
Not really.
The second continue is redundant (your code would continue anyway).
Try using the Switch statement. It will make your code more readable.
One nicer way to do it would be to use switch statements, something like this:
void f()
{
int r;
boolean condition = true;
while(condition)
{
outerloop:
r = check();
switch(r){
case 0: break outerloop;
case 1: return;
case 2: continue;
case 3: condition = false;
}
You might want to think about re-formulating your logic as a state machine. It might simplify things, and will probably make the logic easier to follow.
Related
I am learning java, and i got stuck in a stupid situation.
I could just throw all my code in here, but it would only confuse you even more. So I converted my logical thinking into this:
if (a)
{
*instruction 1*
}
if (!a && b && !c)
{
*instruction 2*
}
if (!a && b && c)
{
*instruction 3*
}
else
{
*instruction 4*
}
All I want to know is if i can simplify this, so i don't use so many "if" statements...
And I'd like to know how you came to your conclusion.
Thanks in advance! (Yes, I'm dumb, help me)
EDIT:
I'm adding a truth-table with every combination of a, b and c:
If a, b and c are local variables or otherwise guaranteed not to change while you go through the if-statements, then you can write your code as:
if (a) {
// instruction 1
} else if (b) {
if (!c) {
// instruction 2
} else {
// instruction 3
}
}
if (a || !b || !c) {
// instruction 4
}
However, it is still pretty complex. Depending on the meaning of a, b and c and how you calculate them, you should probably refactor this code into multiple methods. For example, the if-statement relating to c might fit well into a single-responsibility method.
If you want to verify whether this change is correct, you can create a truth-table with all possible combinations of a, b and c being true or false. You would check which instruction would be performed in your first code, and which instruction gets performed in the new code.
You probably want to use a switch statement to make this more readable.
Something like:
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
The switch statement is a multi-way branch statement. It provides an easy way to dispatch execution to different parts of code based on the value of the expression. Basically, the expression can be byte, short, char, and int primitive data types. Beginning with JDK7, it also works with enumerated types ( Enums in java), the String class and Wrapper classes.
As far as i can see there's a Wrapper Class for Booleans.
boolean result = switch (ternaryBool) {
case TRUE -> true;
case FALSE -> false;
case FILE_NOT_FOUND -> throw new UncheckedIOException(
"This is ridiculous!",
new FileNotFoundException());
// as we'll see in "Exhaustiveness", `default` is not necessary
default -> throw new IllegalArgumentException("Seriously?! 🤬");
};
https://blog.codefx.org/java/switch-expressions/
In multiple conditions, I would use the switch statement to make it easier to read.
https://beginnersbook.com/2017/08/java-switch-case/
I was wondering if there is any better way to handle n no. of if/else-if block in Java.
I have a situation where I need to print different values based on n no. of if/else-if/conditions blocks like
if(p==1 && q==r)
System.out.println("Condition 1");
else if(r==p && q==9)
System.out.println("Condition 2");
else if(z==1 && s==r)
System.out.println("Condition 3");
else if(p==1 || x==r && y==7)
System.out.println("Condition 4");
else if(q==z && y==r || p==4)
System.out.println("Condition 5");
else if(x==z && r==5 || z==30)
System.out.println("Condition 6");
else if(s==1 || q==x)
System.out.println("Condition 7");
else if(r==14 || q==r++ || z==y)
System.out.println("Condition 8");
else if(q==18 && s==r || p==90)
System.out.println("Condition 9");
else if(y==19 || q==89)
System.out.println("Condition 10");
...
Is there any other way to handle it instead of putting multiple if/else if statements so that if later on any new condition come, it will be easy to handle it.
The real answer here: don't do that.
In good OO design, you solve this problem in very different ways; for example by using polymorphism. You actually want to avoid having many different sources of information, to then make decisions on that.
In your case; I would be thinking towards FSMs and the state pattern for example.
What I mean is: your code is showing a certain "approach" towards solving a problem. And as long as you keep that approach as is, you are only talking about finding ways to express your solution in the "least ugly" way.
Instead, you should step back and look into approaches that can be expressed in "really beautiful" ways.
Thus: there is no "simple" direct answer to your question. You have to step back and have a close look at the requirements you want to fulfill; to then design a better, "more OO" solution to that.
The minimal thing here: you could start by declaring an enum like:
public enum Condition {
A, B, C, ...
and then you would have some factory method that hides all those statements; like:
Condition currentCondition = determineCondition(p, q, r, z);
switch(currentCondition) {
case A:
Meaning: you want to at least "centralize" that knowledge somewhere to avoid code duplication. But again; that is just like putting some new color on an old, rusty car. It helps for the moment, but doesn't really improve things.
Regarding your comments: yes, the switch is only marginally "better" than if elses. But as you said: you can't make too many chances, so at least you want to have exactly one piece of code that determines state.
But in the end: I think you are approaching this on a wrong level. You are probably dealing with some kind of complicated business logic; and you want to solve that on a low level like this. But nothing you do on such a level will lead to a robust, long-term maintainable solution. Probably the real solution is to step back and look into using some kind of workflow engine.
You can make a Condition (interface or superclass) which accepts all your variables:
public interface Condition {
boolean isConditionMet(int p, int q, int r, int s, int x, int y, int z);
void performAction();
}
For each single Condition you can override/implement a boolean method isConditionMet().
public class C1 implements Condition {
public boolean isConditionMet(int p, int q, int r, int s, int x, int y, int z) {
return p == 1 && q == r;
}
public void performAction() {
System.out.println("Condition 1");
}
}
Then you can put all conditions in a collection, and for each Condition you have you can ask:
if (condition.isConditionMet())
condition.performAction();
Now each Condition object itself is responsible for when it should act, and what it should do then. A perfect separation of concerns.
Downvote bait
When you say "if any new condition come" do you mean you are willing to modify the code if a new condition comes, or must the code adapt without being modified? If the former, I think you've done it the best way. (Though, I would add an if (false){} at the top, so all the real cases look the same, making it easy to rearrange them.) If the latter, then a table-driven approach is needed. Performance is not an issue if every case has a print statement. If you do care about performance, then put the most common cases first.
If you care even more about performance, have a tree of if-statements, rather than a ladder. So, for example, have something like this, so you're not repeatedly asking the same sub-question:
if (p == 1){
.. all the cases where p is 1
} else {
.. all the other cases
}
There may be other OO-related ways to write this, but none of them will be faster or easier to modify than this.
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.
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.
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