I have an old code that needs to be brought back to life, it utilises around 10-15 booleans that dance around the entire class, like so:
if (condition)
{
bool1 = true
}
if (condition)
{
bool2 = true
}
...
then
if (bool1 == true && bool2 == true && bool3 == false)
{
do something
}
else if (bool1 == true && bool2 == false && bool3 == false)
{
do something
}
...
Could coding this way be avoided? Are there better ways to implement this? Perhaps utilising a map?
I would like to improve readability and overall performance, since this piece of code is over 1,000s lines long.
After feedback adding more specific example:
boolean bool1 = false, bool2 = false, bool3 = false, bool4 = false, bool5 = false,
bool6 = false, bool7 = false, bool8 = false, bool9 = false, bool10 = false;
if (string_object.startsWith("Pattern1"))
{
bool1 = true
}
if (string_object.startsWith("Pattern2")
{
bool2 = true
}
if (string_object.startsWith("Pattern3")
{
bool3 = true
}
if (string_object.startsWith("Pattern4")
{
bool4 = true
}
if (string_object.startsWith("Pattern5")
{
bool5 = true
}
// and so on...
if (system_type.equals("type1"))
{
if (bool1 == true && bool2 == true && bool3 == false)
{
system_value.set("value1")
}
else if (bool1 == true && bool2 == false && bool3 == false)
{
system_value.set("value2")
}
else if (bool1 == true && bool3 == false && bool4 == true)
{
system_value.set("value3")
}
}
else if (system_type.equals("type2"))
{
if (bool1 == true && bool2 == true && bool4 == true)
{
system_value.set("value1")
}
else if (bool1 == true && bool3 == false && bool5 == true)
{
system_value.set("value4")
}
else if (bool1 == true && bool3 == false && bool4 == true)
{
system_value.set("value5")
}
}
// and so on...
There are a few things you can do.
as others have mentioned, code like this:
if (condition)
{
bool1 = true;
}
Can be compressed to:
bool1 = (condition);
Another useful tool is one of Martin Fowler's refactors - Decompose Conditional.
An example of this would be something like changing this:
if (bool1 == true && bool2 == true && bool3 == false)
{
do something
}
else if (bool1 == true && bool2 == false && bool3 == false)
{
do something
}
To something like this:
if (firstCondition())
{
do something
}
else if (secondCondition())
{
do something
}
private boolean firstCondition() {
return (bool1 && bool2 && !bool3 );
}
private boolean secondCondition() {
return (bool1 && !bool2 && !bool3);
}
Decomposing complex conditionals like this makes your code easier to read and maintain.
You can construct bit maps from your booleans, and encode desired combinations as integers.
Here is an example: let's say you need three booleans, flag0, flag1, and flag2, and you need to check five different combinations of the flags:
flag2 flag1 flag0 Action
----- ----- ----- ----------
true false false ActionOne
true true false ActionTwo
true false true ActionThree
false false true ActionFour
false true true ActionFive
Then you can build flags as follows:
int flags = 0;
if (condition0) flags |= (1 << 0);
if (condition1) flags |= (1 << 1);
if (condition2) flags |= (1 << 2);
Now each combination of conditions is encoded as a unique number between zero and seven, inclusive, so it could be checked with a switch statement:
switch(flags) {
case 4: actionOne(); break; // 1 0 0
case 6: actionTwo(); break; // 1 1 0
case 5: actionThree(); break; // 1 0 1
case 1: actionFour(); break; // 0 0 1
case 3: actionFive(); break; // 0 1 1
}
Most of the time this antipattern is due to developers not wanting to create a subclass for just one new behavior. If that is the case, polymorphism could help.
Assume you have the following class:
public class Animal {
private final boolean isCat;
private final boolean isReptile;
private final boolean isDog;
private Animal(final boolean isCat, final boolean isReptile, final boolean isDog) {
this.isCat = isCat;
this.isReptile = isReptile;
this.isDog = isDog;
}
public static Animal getLizard() {
return new Animal(false, true, true);
}
public static Animal getDog() {
return new Animal(false, false, false);
}
public String seeStranger() {
final StringBuilder result = new StringBuilder(this.toString());
if (isDog) {
result.append(" barks and");
} else if (isCat) {
result.append(" meows and");
}
if (isReptile) {
result.append(" crawls away.");
} else {
result.append(" walks forward.");
}
return result.toString();
}
}
What you really want are multiple classes with differing behavior:
public abstract class Animal {
public static Animal getLizard() {
return new Lizard();
}
public static Animal getDog() {
return new Dog();
}
public abstract String seeStranger();
private static class Lizard extends Animal {
#Override
public String seeStranger() {
return this.toString() + " crawls away.";
}
}
private static class Dog extends Animal {
#Override
public String seeStranger() {
return this.toString() + " barks and walks forward.";
}
}
}
Depending on your use case, you might find it easier to dispense with Boolean variables altogether and just put the conditions inline in the control flow statements. For example, you could change this:
if (condition1)
{
bool1 = true
}
else if (condition2)
{
bool2 = true
}
...
if (bool1 == true && bool2 == true && bool3 == false)
{
do something
}
else if (bool1 == true && bool2 == false && bool3 == false)
{
do something
}
...
to be something more like this:
if (condition1 && condition2 && condition3)
{
do something
}
else if (condition1 && (not condition2) && codition3)
{
do something
}
...
You might also be able to simplify your conditions. For example, there might be a condition4 equivalent to condition1 && condition2 that doesn't use &&. Consider condition1 := x <= 100 and condition2 := x >= 100. condition1 && condition2 is totally equivalent to x == 100, and I would definitely recommend changing
...
bool1 = (x >= 100);
...
bool2 = (x <= 100);
...
if (bool1 == true && bool2 == true) { ... }
...
to this instead:
...
if (x == 100) { ... }
...
I hesitate to go so far as to call the explicit use of Boolean variables an antipattern, but I tend to prefer to keep Booleans as R-values whenever possible.
In this case I would recommend leaving the booleans alone, if they're well labeled
But a neat thing can be done if they are closely related (ie direction, N/S/E/W), called bitmasks
Related Stack Overflow post: what is a bitmask and a mask
They're useful for direction if you have a grid of streets, each street intersection can have N/S/E/W roads coming out of it, can be defined as 4 bits of a number
Let's define a few constants
N=1 (0001)
S=2 (0010)
E=4 (0100)
W=8 (1000)
An intersection with roads in N and E would be N|E
N|E=1|4=5 (0101)
A full + intersection (NSEW) would be N|S|E|W
N|S|E|W=1|2|4|8=15 (1111)
If you're adding to a bitmask, newMask = oldMask|direction
Let's add S to our NE mask
int newMask = oldMask | S
oldMask was 0101, S is 0010, newMask becomes 0111
It also has an easy way to check if a direction exists
If we want to check if oldMask contains N
boolean N? = (oldMask & N) != 0
oldMask & N will isolate the N bit, making the returned value either be N or 0
Related
I'm suppose to create a code that recognizes if my hand has the same card faces
public static boolean sameFace(String hand) {
hand = "s9s7s2sQsK";
char f = hand.charAt(0);
if( hand.charAt(0)==hand.charAt(2) && hand.charAt(0)==hand.charAt(4)
&& hand.charAt(0)==hand.charAt(6) && hand.charAt(0)==hand.charAt(8));
return (hand.charAt(0) == hand.charAt(2) && hand.charAt(0) == hand.charAt(4)
&& hand.charAt(0) == hand.charAt(6) && hand.charAt(0) == hand.charAt(8));
sameface = hand;
if (hand==true;)
return (hand==true;) ;
}
As can be seen above, if all positions are the same characters, it comes true(False, if even one isn't the same.) How can I then use the result of that "return" to let my program recognize it has the same faces or not? If that is even possible.
From what i know, based on my code, it's saying "Yes, positions x=y=z are the same" how can I then tell it "Since they are the same, they have the same card faces."
I tried to put this at the end
sameface = hand;
if (hand==true;)
return (hand==true;) ;
Basically I'm trying to say that when the "hand" return statement is true, then samefaces is true. Meaning that the faces are the same. And if it's false it'll return false.
Basically I'm trying to say that when the "hand" return statement is true, then samefaces is true. Meaning that the faces are the same. And if it's false it'll return false.
You do that simply by returning the result of the expression:
public static boolean sameFace(String hand) {
char f = hand.charAt(0);
return f == hand.charAt(2) &&
f == hand.charAt(4) &&
f == hand.charAt(6) &&
f == hand.charAt(8);
}
Or if you want to be friendly to a different number of cards, use a loop:
public static boolean sameFace(String hand) {
char f = hand.charAt(0);
for (int i = 2, len = hand.length(); i < len; i += 2) {
if (f != hand.charAt(i)) {
// Not a match
return false;
}
}
// All matched
return true;
}
public static boolean isValidReferenceCode(String rc) {
boolean validCode = true;
if (rc.length() != 6 ) {
validCode = false;
} else if ( !Character.isLetter(rc.charAt(0)) ||
!Character.isLetter(rc.charAt(1)) ||
!Character.isDigit(rc.charAt(2)) ||
!Character.isDigit(rc.charAt(3)) ||
!Character.isDigit(rc.charAt(4)) ||
!Character.isLetter(rc.charAt(5))) {
validCode = false;
} else if ( (!rc.substring(5).matches("B")) || (!rc.substring(5).matches("N")) ) {
validCode = false;
}
return validCode;
}
This is my validation method inside a big program, I need a validation that requires the user to input at least 6 characters, first two being letters, next three being digits, and the last character either a "B" or "N" right now it's not doing that. After some trial and error, the first two IF statements seem to be correct and work when I delete the 3rd if statement about substrings, am I using the correct Syntax here? Would really appreciate help!
Find below logic , it will work . Better to use regular expressions .
public static boolean isValidReferenceCode(String rc) {
boolean validCode = true;
String pattern= "^[a-zA-Z]{2}[0-9]{3}[BN]}$";
if (rc.length() != 6) {
validCode = false;
}
validCode = rc.matches(pattern);
return validCode;
}
Another way to solve it is to use the original code with:
} else if ( (rc.charAt(5) != 'B') && (rc.charAt(5) != 'N') ) {
You need both to be misses (i.e., use an && instead of an ||).
Instead of a cascade of ifs and negative logic, you can do the entire test more clearly in a single positive-logic expression:
public static boolean isValidReferenceCode(String rc) {
return
rc.length() == 6 &&
Character.isLetter(rc.charAt(0)) &&
Character.isLetter(rc.charAt(1)) &&
Character.isDigit(rc.charAt(2)) &&
Character.isDigit(rc.charAt(3)) &&
Character.isDigit(rc.charAt(4)) &&
(rc.charAt(5) == 'B' || rc.charAt(5) == 'N');
In an example in class we were given this method as part of a bigger problem:
public boolean isWinner()
{
return ((points == 4) || (score == 4));
}
My impression of boolean type methods was that they HAVE to return true/false like "return true;" In this example there is no where indicating whether it is returning true/false so if points == 4 does it return true? and if score ==4 does it return false? or is it if either are true then the entire return statement is true?
If either points == 4 or score == 4 is true, the whole thing will be true. All boolean expressions evaluate down to either true or false.
This expression:
return ((points == 4) || (score == 4));
Will either return true or false.
|| is the OR operator. Which for two expressions has the following truth table:
T T = T
T F = T
F T = T
F F = F
So if both points and score are false then the function will return false. Otherwise it will return true.
return ((points == 4) || (score == 4));
Execution of above will result in return true or return false
From specification.
The value produced by the == operator is true if the value of the left-hand operand is equal to the value of the right-hand operand; otherwise, the result is false.
also read about || operation in specification I hope that will clear your doubts
This
return (points == 4) || (score == 4);
is the same as
boolean ret = (points == 4) || (score == 4);
return ret;
which is the same as
if (points == 4) return true;
if (score == 4) return true;
return false;
You should take a look at the Java truth tables for || and &&. This will help give you an understanding of boolean results.
As your question stands, it will return true if either of those statements are true and false if they are both false.
There is only one exception in that code.
In the case that points/score are Integer referencing null, would cause an exception.
public class Snippet {
private Integer points;
private Integer score;
public boolean isWinner() {
return ((points == 4) || (score == 4));
}
public static void main(String[] args) {
System.out.println(new Snippet().isWinner());
}
}
Output:
Exception in thread "main" java.lang.NullPointerException
at snippet.Snippet.isWinner(Snippet.java:8)
at snippet.Snippet.main(Snippet.java:13)
Compare three boolean values and display the first one that is true.
Hey guys, I am trying to write a program that compares three boolean values and displays the first true one. I am comparing three words for their length, and it will display the longest. The error that I am getting is that my else tags aren't working. Take a look at the code.
//Check which word is bigger
if (len1 > len2)
word1bt2 = true;
if (len2 > len3)
word2bt3 = true;
if (len1 > len3)
word1bt3 = true;
//Check which word is the longest
if (word1bt2 == true && word1bt3 == true);
System.out.println(wor1);
else if (word2bt3 == true);
System.out.println(wor2);
else System.out.println(wor3);
I have set boolean values for word1bt2, word2bt3 and word1bt3. In eclipse, I am getting a syntax error under the elses in my code above. Any help would be great!
if (word1bt2 == true && word1bt3 == true);
Is wrong, you need to remove the semicolon:
if (word1bt2 == true && word1bt3 == true)
Same for the elses
else (word2bt3 == true);
Is wrong too, it should be
else if (word2bt3 == true)
Side note: boolean values can be used as condition, so your if statements should be
if (word1bt2 && word1bt3) // The same as if (word1bt2 == true && word1bt3 == true)
How to compare three boolean values?
Dont!
If you find yourself needing to compare three variable you may as well cater for any number of variables immediately - there's no point hanging around - do it properly straight away.
public String longest(Iterator<String> i) {
// Walk the iterator.
String longest = i.hasNext() ? i.next() : null;
while (i.hasNext()) {
String next = i.next();
if (next.length() > longest.length()) {
longest = next;
}
}
return longest;
}
public String longest(Iterable<String> i) {
// Walk the iterator.
return longest(i.iterator());
}
public String longest(String... ss) {
// An array is iterable.
return longest(ss);
}
Remove the ; and change it with brackets {}.
if (word1bt2 && word1bt3) {
System.out.println(wor1);
} else if (word2bt3) {
System.out.println(wor2);
} else {
System.out.println(wor3);
}
Issue with the else blocks: use {} insteaad of () to enclose instructions...
Remove the ; at the first if!!!!! - Quite common mistake, with very puzzling results!
//Check which word is the longest
if (word1bt2 == true && word1bt3 == true) { //leave ; and always add bracket!
System.out.println(wor1);
}
else if(word2bt3 == true)
{
System.out.println(wor2);
}
else {
System.out.println(wor3);
}
if you need a condition in an else branch, you have to use if again - plain else won't have such a feature...
ALWAYS use brackets for bodies of if statements, loops, etc!!!
Be extremely careful NOT to use ; in the lines that don't behave well with it:
if statements
for loops
while() {...} loops' while statement
try this, if lenght are equal then s1 is considered as Bigger. Also i have not added null check
public class Test {
public static void main(String[] args) {
String word1 = "hi";
String word2 = "Hello";
String word3 = "Hell";
String Bigger = null;
if(word1.length() >= word2.length() && word1.length() >= word3.length() ){
Bigger = word1;
}else if(word2.length() >= word1.length() && word2.length() >= word3.length()){
Bigger = word2;
}else if(word3.length() >= word2.length() && word3.length() >= word1.length()){
Bigger = word3;
}
System.out.println(Bigger);
}
}
I actually try to convert four different Boolean into true/false.
My case is,
True false false false Then true else false
false True false false Then true else false
false false True false Then true else false
false false false True Then true else false
I tried like this,
int a=1;
int b=0;
int c=0;
int d=0;
int cnt=0;
// A block of code will be executed only when any one of the four variables is 1 and
//the rest of them is 0. and another block will be executed when the above mentioned
//condition become false.
if (a==0) { cnt+=1; }
if (b==0) { cnt+=1; }
if (c==0) { cnt+=1; }
if (d==0) { cnt+=1; }
if (cnt==3) { // true block } else { //false block }
The above code is working perfectly fine, But i had taken a challenge to check this condition in a single if statement. Then i tried like this.
if(!((!(a==0) && !(b==0)) && (!(c==0) && !(d==0))))
{
//true block
}
else
{
//false block
}
The above condition is failing in some combinations(a=1 b=0 c=1 d=1). Can anybody point out what the issue is.? or suggest any new ideas.?
My objective is convert (3 false + 1 true) into true other wise into false.
[Note: I just gave the scenario for understanding purpose only. a,b,c,d value may be differ. See my objective. Don't say answers in favor of 1 and 0]
I think I would use the following method, which makes the algorithm reusable and support any number of arguments. It returns true only if exactly one argument was true.
private boolean oneTrue(boolean... args){
boolean found = false;
for (boolean arg : args) {
if(found && arg){
return false;
}
found |= arg;
}
return found;
}
You can test it like this:
private void test(){
boolean a = false;
boolean b = true;
boolean c = false;
boolean d = false;
System.out.println(oneTrue(a,b,c,d));
}
Shortest pure bool solution which I can suggest:
System.out.println((a | b) ^ (c | d)) & ((a ^ b) | (c ^ d));
But in your program already already used 1 and 0, if it variables always 1 and 0, you may not use boolean just use following:
if (a + b + c + d == 1)
{
// true
} else
{
// false
}
if this varibales may have any values. In this case I recommend convert it to 1 and 0 instead of boolean and again can simply calculate sum.
How about this?
boolean a = true;
boolean b = false;
boolean c = false;
boolean d = false;
if ((a ? 1 : 0) + (b ? 1 : 0) + (c ? 1 : 0) + (d ? 1 : 0) == 1) {
System.out.println("You win!");
}
[edit]... or here's another way to do it :
if ((a ^ b ^ c ^ d) & ((a & b) == (c & d))) {
System.out.println("**XOR** You win!");
}
You can use the following expression:
a && !(b || c || d) ||
b && !(a || c || d) ||
c && !(a || b || d) ||
d && !(a || b || c)