JAVA looping logic error with NOT .equalsIgnoreCase() - java

I'm trying to use equalsIgnoreCase() in a while loop to try and check if something other than what was intended to be written was written by using the NOT (!) operator. For example:
String temp="A";
boolean x =(!temp.equalsIgnoreCase("a")) ;
See, this works with a while loop. If it's not A, it will keep looping but this next line does not
boolean x =(!temp.equalsIgnoreCase("a") || !temp.equalsIgnoreCase("b")) ;
This does not seem to work anymore. This returns true, no matter what you type, even if it is a or b. So when I use the whole line of code to check for any of the letters that are not suppose to be used:
while (!temp.equalsIgnoreCase("A") || !(temp.equalsIgnoreCase("B")) ||!temp.equalsIgnoreCase("D")|| !temp.equalsIgnoreCase("P") || !temp.equalsIgnoreCase("S"))
{ ***Do Code***}
it loops whatever you put in, even if it will equal one of the letters.
When there is more than one !temp.equalsIngnoreCase, the code does't work with OR (||).
The only way I can get it to work is if I change the OR to AND
while (!temp.equalsIgnoreCase("A") && !(temp.equalsIgnoreCase("B")) && !temp.equalsIgnoreCase("D")&& !temp.equalsIgnoreCase("P") && !temp.equalsIgnoreCase("S"))
Even though I seem to have found a solution, I still don't understand why OR doesn't work but AND does. I removed the NOT to see if everything works, and it seems to loop perfectly when one of the letters is entered.

it loops whatever you put in, even if it will equal one of the letters.
Yes, of course it does.
You're asking it to keep going while it isn't A or it isn't B. Well nothing can be both A and B... if the value is equal to B then it won't be equal to A so the first operand will keep the loop going. If the value is equal to A then it won't be equal to B so the second operand will keep the loop going.
Your solution of changing to AND is correct - you want the value to not be A and not be B (i.e. it's neither A nor B).
Alternatively, you could use OR internally, but put a NOT around the whole thing:
while (! (temp.equalsIgnoredCase("A") || temp.equalsIgnoreCase("B") || ...))

I still don't understand why OR doesn't work but AND does
The expression using || will always be true at any given value of temp. Because, temp cannot be both a and b at the same time. If it is a, then the 2nd part of || will be true, and if it is equal to b or any other value, the first part will be true, thus making the entire expression true in both the cases.
With &&, your while will only be true, if temp is neither of a nor b.
Alternatively, if you are going to test temp against many values, you can change your while condition to look simpler:
while (!"ABDPS".contains(temp.toUpperCase())) {
}

its a foul logic. the code
(!temp.equalsIgnoreCase("A") || !(temp.equalsIgnoreCase("B")) ||!temp.equalsIgnoreCase("D")|| !temp.equalsIgnoreCase("P") || !temp.equalsIgnoreCase("S"))
means
if char is not A, or not B, or not D, or not P, or not S. It will always evaluate to true, since is char is A, it will neither be B,D,S nor P. so is for the others.
if you want it to be OR logic, it should be:
(!(temp.equalsIgnoreCase("A") || (temp.equalsIgnoreCase("B")) ||temp.equalsIgnoreCase("D")|| temp.equalsIgnoreCase("P") || temp.equalsIgnoreCase("S")))
which means, not when the char is either of A, B, D,S or P

This is all about logic.
A OR B means that is is true when A is true or B is true or both are true.
In your special case it is only possible that one of your equalsIgnorecase() can ever work, so you wrote something like a tautology which means an endless loop.
You can read about boole algebra here: http://en.wikipedia.org/wiki/Boolean_algebra_%28structure%29
Kind of some theory but it explains what you need to know when you write boolean expressions.
Hope this helps :)

Related

Java & and && operators troubles

I'm trying to figure out why & operator throws an exception and suspends my program but when I use && operator the program works with no errors.
Here is the portion of the code:
books is an arraylist of objects Book.
areYouBook returns true if the book's ISBN I'm looking for matches a.
The method findBook checks if I already have the book in the arraylist. When the method returns null, it means I have to create the book and add it to the ArrayList.
Thank you very much for your help!
public Book findBook(int a){
int i=0;
while((i<(books.size()))&!((books.get(i)).areYouBook(a)))
i++;
if(i<(books.size()))
return books.get(i);
else
return null;
}
I can tell you from here that the difference between the & operator and the && operator is that && will check the first expresion, and if it evaluates to false, then it will simply break from the check, but the & operator will run the following expression regardless of whether or not the first one turned out to be false.
So, the code you have written will check (i<(books.size())), and whether or not that turns out to be false, !((books.get(i)).areYouBook(a)) will still be executed.
If however, you used && and (i<(books.size())) was false, the second part of your check, which is !((books.get(i)).areYouBook(a)), will not be executed.
I hope this helps.
Edit:
You mentioned an error being thrown when you used the & operator instead of the && operator. Since the & operator does run the second expression even if the first one is false, I'm wondering if your second expression is actually throwing an error, and is getting called when you use &.
Edit 2:
Ok. Lets say that books has a size of 12 (indexes 0-11) just for demonstration. So, when you use the & operator, your while loop runs until i is 12. When i is 12, the loop executes (i<(books.size())) (which returns false) and CONTINUES to execute !((books.get(i)).areYouBook(a)). Inside the second expression, books.get(i) is being called, when i is 12. The books list only goes from indexes 0-11, throwing a java.lang.IndexOutOfBoundsException.
java conditional operators says:
the operators && and || exhibit "short-circuiting" behavior, which means that the second operand is evaluated only if needed.
the logical AND operator && will be short-cuircuting if the left side condition is false, on the other hand, when the left side condition is false the right side condition is never be executed.
but the bitwise & operator performs a bitwise AND operation.
The logical AND that you're trying to use is represented by the && symbol i.e. True && False resolves to False. The single ampersand "&" represents a bitwise AND i.e. 0101 & 0100 resolves to 0110.

Best way to only test for a condition if another condition is false

So I've got a function that uses an arraylist, and I want it to do something like this:
if(/*1*/ theArrayList.size() == 0 || /*2*/ theArrayList.get(someNumber).someBoolean){....
The problem is that this function can be triggered at a time when the ArrayList is empty, which would cause an error in the second half of the if statement. So I changed it to this:
if(theArrayList.size() == 0){
//do some code
} else if(theArrayList.get(someNumber).someBoolean){
//do the same code as above
} else...
But I feel like this is obtuse and that there must be an easier way. So how can I make it only test for the second half of the if statement if the first half has already been proven false?
This will not actually cause an error on the second half of the if statement. You're using || which is a short-circuit OR. That means that if the first part is true (the array list is empty) then the second part will not be evaluated.

simple control structures (if statements)

I'm a newbie in the world of Java and currently learning IF statements.
In the text-book I'm currently using, it is asking me to 'rewrite the following nested if statements without using any nesting'.
Now, I have two questions. The first one is in regards to whether or not I'm reading this in the right sequential order and the second one on whether there is a conflicting condition in lines 1 and 2 (a paradox). The problem question they ask me to rewrite is the following:
if ( a < b )
if (a >= b)
x = z;
else
x = y;
else
x = z;
To my limited understanding of if statements, the sequential order would probably be the following:
if variable a is less than b then execute the first statement (which is another if statement) and execute the SECOND else statement if the condition is false.
if variable a is equal to or greater than b then execute the accompanying statement or if the condition is false then execute the FIRST else statement.
Am I reading this correctly so far? I apologise if I am making things hard to understand.
Now onto the second question; if the first if statement comes out as true (a being less than b) how can a be potentially greater than or equal to b when the first condition is already true? Wouldn't that be conflicting?
Thanks for helping :)
You understand it right.
The code is actually equivalent to:
if (a < b)
x=y;
else
x=z;
If a < b, than for sure (a >= b) is false, and you go to the first else statement. If not - the statement in the second else is ran.
This is true almost for every language and every variable type, but might not be true in some cases, if you overloaded the operators inconsistently.
Another case, is if you implement the operator a < b, such that it will change the value of a.
However, such cases should not exist in normal code.
Following the logic of the code you posted, it is equivalent to:
if (a < b)
x = y;
else
x = z;

Do loop while input isn't a or b?

I'm doing the finishing touches for a class project and I'm adding in a safety net for one of my user inputs. I have it set so that if the user puts in "1" or "2", the data they enter will be displayed in different ways. I want to add a method that prevents the user from entering anything other than "1" or "2". Here is the code for it.
do
{
System.out.println("Please type either '1' or '2'.");
Scanner scan = new Scanner(System.in);
a = scan.nextInt();
}
while (a != (1||2));
//after user enters 1 or 2, return the choice
return a;
I've been reading about the operands and logic, but I'm kind of stuck. I've been badgering my teacher the whole way through so I figured I'd give him a break since I'm not his only student. My error is saying "bad operand types for binary operator '||'.
This is a common misconception when learning programming.
You, as a human, can easily read the statement which reads like this: "while a is not 1 or 2", but the computer has to follow certain rules, and one of the rules is that "or" takes precedence.
What this means is that it first triest to figure out what "1 or 2" means, since basically, your statement is similar to this:
while (a != SOMETHING);
|| in the Java language is "logical or", which translates to this: Take the two values (called operands) on each side of the || (called the operator), and combine them according to the rules of "logical or".
"logical or" uses two boolean values, which can only be True or False, and since you asked it to use the operator with numbers, that's why you get that particular error message.
If you had tried using the single pipe, |, the compiler might have stopped complaining, but it would still not do what you want it to do.
1 or 2 when dealing with numbers, using the | operator, which is the "bitwise or" operators, you would get the two numbers combined to form the number 3. You can read more about "bitwise operators" if you want to know why.
In short, you cannot write your comparison like this.
In programming languages, comparisons are done two values at a time, ie. one against another, so your only choice is to expand the expression to compare twice.
Here is some equivalent expressions which will give you what you want:
while (a != 1 && a != 2);
or this:
while (!(a == 1 || a == 2));
To be hones, I like the first better.
It is (a != 1 && a!=2) - You actually want to exit the loop when a is either 1 or 2.
You need to do separate conditional statements for a!= 1 and a!= 2.
Your conditional statement should look something like this:
(a!=1) && (a!=2)
You can't treat an int like pseudo-regex. Replace
while (a != (1||2));
with
while (a != 1 && a!= 2);
try this in your while loop condition
((a!=1) && (a!=2))
You have to write
while (a != 1 && a != 2)
because it's the equivalent of not (a == 1 || a == 2)
The binary operator '||' needs two boolean operand on both side. Since, your operands are integers, this is a syntax error.
You should do it in this way:
do{
// core of the loop...
}while(a!=1 && a!=2);
The problem here is you are trying to write code that makes sense read as English, but it doesn't work like that. The || operator takes two expressions and returns if one or the other is true. That means what you have written doesn't make sense.
The simplest way to replace this is to expand it out:
a != 1 && a != 2
(We need to use && as we are checking that neither of them is true).
Note that this can become verbose and awkward. Alternatively, a good replacement (given you have a lot of values to check) is a membership check in a collection (a Set is a good choice as you are guaranteed a O(1) membership test). E.g:
Set<Integer> possibles = new HashSet<Integer>();
Collections.addAll(possibles, new Integer[] {1, 2, ...});
while (!possibles.contains(a)) {
...

Should I separate AND with two if statements?

I have the following lines in my code:
if (command.equals("sort") && args.length == 2) {
//run some program
}
Someone suggests that I should use two separate if statements because there's no need to evaluate any of the other if statements if the command does not equal to "sort"​, regardless of whether or not the args length is correct.
So according to that that, I need to rewrite my code to:
if (command.equals("sort")) {
if (args.length == 2) {
//run some program
}
}
I know they both do the job, but my question is which one is better and more efficient?
No, that's not true. They call it short circuit, if the first condition evaluates as false, the second one would not be evaluated at all.
Well, since && is a short-circuit operator. So both the if statements are effectively the same.
So, in first case, if your command.equals("sort"), returns false, the following condition will not be evaluated at all. So, in my opinion, just go with the first one. It's clearer.
As stated, short circuit will cause the program to exit the if statement the moment a condition fails, meaning any further conditions will not be evaluated, so there's no real difference in the way the two formats are evaluated.
I would like to note that code legibility is negatively affected when you have several if statements nested within each other, and that to me is the main reason not to nest. For example:
if( conditionA && conditionaB && !conditionC ){
// Do Something
}
is much cleaner than:
if( conditionA ){
if( conditionB ){
if( !conditionC ){
// Do Something
}
}
}
Imagine that with 20 nested if statements? Not a common occurrence, sure, but possible.
They are the same. For your first example, any modern runtime will ignore the second expression if the first expression is false.
short circuiting is better which is done by && if you are check null case for a value and then apply a function on that object, short circuit operator works well. It stops from condition 2 to be executed if condition 1 is false.
ex:
String s=null;
if(s!=null && s.length())
This doesnt throw exceptions and also in most cases you save one more if check.
If the conditions are in the same order, they are exactly the same in terms of efficient.
if (command.equals("sort") && args.length == 2)
Will drop out if command.squals("sort") returns false and args.length will never be checked. That's the short-circuit operation of the && operator.
What it comes down to is a matter of style and readability. IMO When you start chaining too many together in a single if statement it can get hard to read.
Actually, it is called [Lazy_evaluation]: http://en.wikipedia.org/wiki/Lazy_evaluation
That's not really the question but note that if you want the two if evaluated, you can use & :
if (methodA() & methodB()) {
//
}
instead of
boolean a = methodA();
boolean b = methodB();
if (a && b) {
//
}
yeah, their suggestions are completely right. What I suggest you is to write the first check as:
"sort".equals(command)
Maybe it does not make sense in this case but in future. Use the static type first so you never need a null check before

Categories