Checking an input in Java [duplicate] - java

This question already has answers here:
Java do while loop making string testing act differently
(3 answers)
Closed 6 years ago.
First let me start off by saying I'm new to Java and I'm not a professional programmer but I have written several macros in VBA.
I'm trying to help my son with his high school Java assignment. In the assignment there is a point where the user has a Y or N input. I can't figure out why this code doesn't work.
// Wait for user to press Y or N
do{
playAgain = input.next();
} while (!playAgain.equalsIgnoreCase("n") || (!playAgain.equalsIgnoreCase("y"));
It works if I only check for one condition.

Your logic says to continue looping so long as the input does not equal n/N or y/Y. This will always be true for both yes and no inputs, and in fact all inputs. If no is entered, the first condition would fail, but the second would be true, and vice-versa for yes.
To remedy this, you should && together the two conditions:
do {
playAgain = input.next();
} while (!playAgain.equalsIgnoreCase("n") && (!playAgain.equalsIgnoreCase("y"));

|| means OR. So, A || B is true if A is true or B is true. Any Or condition works like this: If first part if true, then second condition is not evaluated. If first is false, then second is evaluated. If either is true, then the result is true.
In your do while loop: !playAgain.equalsIgnoreCase("n") will be true if "y" is equal to your input and vice versa. Either way any one of the condition will always be true in the while loop condition, so the loop will go forever. The solution is mentioned in the answer given above. (use && instead of ||)

Related

Why is BlueJ giving my code an "unreachable statement" error? [duplicate]

This question already has answers here:
Why is this code giving an "Unreachable Statement" error?
(4 answers)
Closed 4 years ago.
As part of my APCS course, I have to fix little problems in a program that's already been written so it can be referenced later. This section is on while-loops and I never learned about unreachable statements so I don't have a clue how to go about fixing it. Attached is the while loop from the program. The error shows up at the first curly bracket.
while( false ) {
//Since the guess doesn't match, determine if it is too low or too high.
if (userGuess > secretNumber) {
System.out.print("Guess number " + numGuesses + " is too LOW. ");
}
else if (userGuess < secretNumber) {
System.out.print("Guess number " + numGuesses + " is too HIGH. ");
}
}
The specific part of the language spec (for Java 9, at least) is Sec 14.21, which describes the conditions under which statements are considered unreachable.
In particular:
It is a compile-time error if a statement cannot be executed because it is unreachable.
and (emphases mine):
A while statement can complete normally iff at least one of the following is true:
The while statement is reachable and the condition expression is not a constant expression (§15.28) with value true.
There is a reachable break statement that exits the while statement.
The contained statement is reachable iff the while statement is reachable and the condition expression is not a constant expression whose value is false.
So, the body of your while loop is considered unreachable because the value of the expression is false, and because it's constant.
To fix it, change either of those conditions; or remove the while loop, since it doesn't logically do anything anyway.
while(false){//...} line will never allow the code to reach either the inner if or the else statement.
The if and else statement will be only evaluated if the condition expression in the while construct is not a constant false, which is not the case in your code.
Hence, the compiler complains that your if & else statements cannot be reached in the current scenario.
You can instead use a variable and assign it the boolean value, as demonstrated by Mr. Elliott Frisch in his answer.
With the loop construct while ( boolean ) the body of the loop is only entered if boolean evaluates to true. A boolean literal false cannot evaluate to true, thus the body is unreachable code.
boolean loopControl = false;
while ( loopControl ) { // <-- this is fine ..
// ...
}

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.

If statement and && gives IDE error 'Syntax error on token "=", <= expected'

I have a simple guess number game. It has a function to ask whether you want tips. It saves the response in a boolean called tips as shown.
while (run) {
while (tinvalidrun){
System.out.println("Do you want any tips? y or n?");
input=in.next();
switch(input){
case "y":
System.out.println("Ok, we will tell you how close you are!");
tinvalidrun=false;
tips=true;
break;
case "n":
System.out.println("Wanna go hard eh? Well, go along!");
tinvalidrun=false;
break;
default:
System.out.println("You pressed the wrong key!\nDo you have butter fingers?");
}
}
Then I have some more code that makes more variables and makes a random number. And finally I get the user input for the guess and test it:
do {
System.out.println("Enter a number: ");
guess = in.nextByte();
times++;
if (guess == gval) {
break;
} else {
System.out.println("No luck! Try again!");
if (tips=true) {
if (guess < gval) {
System.out.println("You are too low!");
}
else {
System.out.println("You are too high!");
}
}
}
I tried putting the tips=true and guess < gval in one if with && but it doesn't work. I did this:
if(guess<gval && tips=true)
It asks me to replace = with <= or something like that. I tried using two if statements but when you say no, it still shows the tips. I tried looking at the brackets but they look fine. Please Help! If there is any simplification or improvements or ideas I can do to my code, they are welcome.
I have more question as well. It crashes (obviously) when you try to type a letter to the integer. I tried using strings and my tinvalidrun loop to avoid this but I can't. Is there a way to do this?
Thanks! :)
Testing equality
You need tips == true, or just if (guess<gval && tips) and if (tips) as you are testing a boolean.
= is an assignment operator, == is an equality operator. It is easy to mix the two up, but the difference is enormous...
Boolean assignment is also an (unexpected) equality test
You say "I tried using two if statements but when you say no, it still shows the tips.". The if statement expects an expression which must have type boolean. Any assignment expression (i.e. tips = true) evaluates as the new value assigned to the variable. From the JLS §15.26.1 Simple Assignment Operator:
At run time, the result of the assignment expression is the value of the variable after the assignment has occurred. The result of an assignment expression is not itself a variable.
Therefore if (tips = true) is valid syntax, because tips = true is both an assignment and also a boolean expression which can therefore be used in an if.
In your case tips = true assigns true to tips (even if it started out false), then returns that new value of tips. The if sees the new value (true) and continues happily on. It is not therefore a test that tips was originally true. By example, this means that the following prints out the "Oops!" text:
boolean tips = false;
if (tips=true){
System.out.println("Oops! This tests as true, but that isn't what we wanted");
}
As you can see, conflating assignment and testing is generally a bad idea. It is usually a mistake if you use = in an if/do/while expression. Sometimes it can help with brevity but it is generally bad practice.
Why doesn't if (guess<gval && tips = true) work?
This is due to operator precedence. In the expression if (guess<gval && tips = true) the operator precedence is < then && and then =, so the compiler no longer evaluates the tips = true part as an assignment of true to tips. You could use brackets to contain tips = true, but as I said above you don't really want the assignment so you can ignore this detail †.
Testing valid byte input
For the last part of your question - you say you get an invalid byte if someone inputs a letter. I'm guessing you get a java.util.InputMismatchException.
You can use Scanner.hasNextByte() to test if the input is a byte before consuming it. If that returns false you can consume and discard the input using nextLine(), print out an error message and loop again.
† Depending on how you were writing your code you may also have seen a message from eclipse such as "The operator <= is undefined for the argument type(s) boolean, Boolean" or from javac such as "error: unexpected type ... required: variable, found: value". None of them tell you much other than your syntax is sufficiently messed up the compiler can't parse it.
if(tips = true) is always true condition because here we have assigned value true to tips.
It will first assign tips to true and then check will be performed in if so your else part is dead due to this code and control will never ever enter in else part.
If you want to check whether tips is true or not then you can just write if(tips) and if you want to check whether it is false than you should write if(tips == false). Where == will check equality while = will assign the value or reference.
Firstly, the test for equality operator is == not =. Secondly, you don't need the operator when testing a boolean. if (tips) ... is enough.
= and == are two completely different things. = is the assignment operator and is used to assign values to variables. == is the equality operator and is used to check if a variable is equal to a certain value, or equal to another variable.
You should be using == instead.
In this line
if(tips=true)
single = means assigning
This should be
if(tips==true)
One equal sign is for assigning as you have done in (guess = in.nextByte();, tinvalidrun=false, tips=true;, and so..) the value in the RHS variable is "put" to the LHS variable. The become equal, i.e they contains the same value. To compare, use two equals sign operator,comparison operator (foo1 == foo2). several operators
There is a little change, use == instead of =
Instead of
if (tips=true)
you would have do
if (tips==true)
Comparison is double ==, single is assignment.
comparison with true is redundancy (but legal)
if(guess < gval && tips==true)
or
if(guess<gval && tips)
Your code fragment doesn't show variable declarations, maybe you compare wrong types too. My fragments assume that tips is boolean.

JAVA looping logic error with NOT .equalsIgnoreCase()

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 :)

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)) {
...

Categories