Below is some code asking the user to input an integer.
public int getValidInput() {
Scanner user_input = new Scanner(System.in);
do {
System.out.println("Enter an integer >=1 and <=10: ");
int number = user_input.nextInt();
} while (number > 10 || number < 0);
return number;
}
The code as shown does not work although when I initialise number outside the do command i.e. set it to int number; and then in the do loop set number = user_input.nextInt(); it does. Why does it work in one case and not the other?
Because in Java, variables are scoped to the block in which they're declared. In your example, the int number = is within the do...while block, and so the variable only exists within that block.
By moving the declaration out of the block, into the block for the method, the variable exists for the method's entire block (including nested blocks).
Your problem is that you have defined number inside your loop. Variables are scoped in Java, so variables declared inside loops or if statements are not accessible outside those loops or if statements. You can fix your code, simply by moving the declaration, as shown below:
public int getValidInput() {
Scanner user_input = new Scanner(System.in);
int number;
do {
System.out.println("Enter an integer >=1 and <=10: ");
number = user_input.nextInt();
} while (number>10 || number < 0);
return number;
}
The curly braces {} of the do-while open up a so called scope (they always do, wether in methods or loops or ifs). Any declaration inside a scope is only visible while you are within that scope, and also in any inner scope opened within the scope.
The condition of your while is outside the curly braces, so it does not see any variable declared within them. If you put the int number; before the do, it's on the same scope level like the while condition, so it, along with the value it gained inside the loop, is visible to the expressions in the condition.
Conditions are used to enter a body from outside that body, so the variable which decides the truth value of condition has to exist before the body.
And as the body block of do-while loop is the code to be executed, therefore the code which decides to execute it must be other than itself.
The scope of a variable restricted to {}. outside of that braces you cannot access. When you initialised it on top it access across both do and while as the scope is increased.
Related
I'm a new programmer trying to practice by making a game.
I want the player to be able to set their own name, as well as answer yes or no as to whether that name is correct.
I did this by using a while loop.
However, since the name is initialized inside the loop, I cannot use it outside. I was wondering if there was anyway to do so.
My code is probably very basic and messy. I apologize for that.
Scanner input = new Scanner(System.in);
String name;
int nameRight = 0;
while (nameRight == 0) {
System.out.println("What is your name?");
name = input.nextLine();
System.out.println("So, your name is " + name + "?");
String yayNay = input.nextLine();
if (yayNay.equals("yes") || yayNay.equals("Yes")) {
System.out.println("Okay, " + name + "...");
nameRight++;
}
else if (yayNay.equals("no") || yayNay.equals("No")) {
System.out.println("Okay, then...");
}
else {
System.out.println("Invalid Response.");
}
}
So basically, I want String name to be initialized inside the loop, so I can use it outside the loop.
The scope of a variable, limits the use of that variable to the scope it is defined in. If you want it used in a broader scope, declare it outside the loop.
However, since the name is initialized inside the loop, I cannot use it outside.
You have defined the variable outside the loop, so the only thing you need to do is to initialize it, as the error message you should get suggests.
String name = "not set";
while(loop) {
name = ...
if (condition)
// do something to break the loop.
}
// can use name here.
The basic problem is that the compiler cannot work out that the variable will be set in all possible code paths. There is two ways you can fix this without using a dummy value. You can use a do/while loop.
String name;
boolean flag = true;
do {
name = ...
// some code
if (test(name))
flag = false;
// some code
} while(flag);
or drop the condition, as you don't need a counter.
String name;
for (;;) {
name = ...
// some code
if (test(name)) {
break;
// some code if test is false.
}
NO, it wouldn't be possible as the scope of the variable declared in the loop is limited to the loop. So the variable is not longer accessible.
while(i < 10){
int x = 2;
i++;
}
Now, the scope of x would be from the point at which it is defined to the end of the enclosing block. So the variable here would be created and destroyed 10 times if i starts from 0.
First there's the "scope", this is the issue you're touching at the moment. The way you have done this so far seems to be a good way of doing it and you WILL be able to use/access the name variable from anywhere in the code after line 2 from what you have linked.
The scope basically says, you can use the variable inside the curly brackets {} that you DECLARED it inside. I assume that you have your code inside some main method at the moment, thus you can access the name variable from anywhere after the line
String name;
as long as you don't try to use it after the closing }, corresponding to a opening { that occurred before name is declared.
SOLUTION: What you have to do to use a variable outside a loop, is to declare it before the loop begins, you don't have to initialize the variable before, but you have to initialize it before you try to use it for anything. In general, if you need to access the variable in a wider area, you must declare that variable before you enter the not-so-wide area.
Notice that by declaring I mean creating the variable reference by using "String" in front of "name". Don't confuse it with initializing it or assigning a value to it, that has nothing to do with the scope, only declaration sets the scope.
I'm trying to make it for that the program will continue to request input of a 5 digit number until the user gives a 5 digit number. When I run the following:
//import scanner to read keyboard input
import java.util.Scanner;
class NumberInverter {
public static void main(String[] args) {
//create a new Scanner object in the memory that reads from the input System.in
Scanner keyboard = new Scanner(System.in);
//display message propmt and input for number
//conditional statement loop to check if the length is any number other than 5
do {
System.out.print("Enter any 5 digit whole number you wish to invert!");
int num = keyboard.nextInt();
int numSize = String.valueOf(num).length();
} while(!isValid(numSize));
}
private static boolean isValid(int numSize){
if(numSize != 5){
System.out.println("Oops! Looks like you gave a number that isn't exactly a 5 digit whole number. Try again!");
return false;
} else return true;
}
}
I get the following error:
NumberInverter.java:20: error: cannot find symbol
} while(!isValid(numSize)); ^
symbol: variable numSize
location: class NumberInverter
1 error
I've tried a bunch of different things, can anyone fluent in java help me out I'm very new?
Thanks ahead of time!
The variable numSize is not in the same scope as the while condition check.
In Java, any variable declared inside a block (a region surrounded by {}) cannot be accessed outside of that block. In this case, since you are declaring numSize right inside the loop, the loop's condition (which is outside that block) cannot access it. Each block creates something called a "block scope", and variables created in there cannot be accessed outside it.
The fix for this is very simple: Declare the variable in the same scope as the while loop. This can be done by putting it right above the do. Notice that you only need to int numSize;, outside, once. You don't put int when you are assigning to it inside the loop, you just do numSize = .... since you are assigning to a previously-declared variable.
You can still assign to the variable from inside the loop, but since it was originally declared outside the loop, stuff outside the loop can access it.
int numSize;
do {
System.out.print("Enter any 5 digit whole number you wish to invert!");
int num = keyboard.nextInt();
numSize = String.valueOf(num).length();
} while(!isValid(numSize));
Some more information about scopes can be found at What is 'scope' in Java?.
Num size is declared inside the loop scope, you're trying to access it outside that scope. For this to work, declare numSize just before the do statement and assign it within the loop. This way, the variable is visible in the whole statement and also inside the loop (for assignment).
int numSize;
do {
// The rest of your code, all variables declared here are
// gone outside the brackets, however you can access the ones
// in outer scopes.
numSize = String.valueOf(num).length();
} while(!isValid(numSize));
See this for more information about different types of scope: https://www.geeksforgeeks.org/variable-scope-in-java/
Create a local variable numSize.
For exemple :
//import scanner to read keyboard input
import java.util.Scanner;
class NumberInverter {
public static void main(String[] args) {
//create a new Scanner object in the memory that reads from the input System.in
Scanner keyboard = new Scanner(System.in);
int numSize;
// int numSize;
//display message propmt and input for number
//conditional statement loop to check if the length is any number other than 5
do {
System.out.print("Enter any 5 digit whole number you wish to invert!");
int num = keyboard.nextInt();
numSize = String.valueOf(num).length();
} while(!isValid(numSize));
}
private static boolean isValid(int numSize){
if(numSize != 5){
System.out.println("Oops! Looks like you gave a number that isn't exactly a 5 digit whole number. Try again!");
return false;
} else return true;
}
}
This method is supposed to return the integer that the user enters as long as it is only an integer (not a String, float, etc.) and as long as that integer is one of the options in the given list of options. I want to use this method throughout my program whenever I give the user a list of options they need to choose from. These lists will have varying sizes thus I pass as an argument the maximum value (maxValue) that the user could possibly choose thus giving the method the size of the list.
//This method handles the players input and checks if the number entered is one of the options listed or not
public static int response(int maxValue){ //the parameter is the number of options in the particular list
response = new Scanner(System.in);
Boolean check = true;
while(check){
try{
int yesOrNo = response.nextInt();
if(yesOrNo > maxValue || yesOrNo <= 0){ //checks if the int entered does not exceed the list size or go below zero
System.out.println("I'm sorry, that number was not one of the options. Please reselect your choice.");
}else{
check = false;
}
}catch(Exception e){ //catches an exception when the user enters a string or anything but an int
System.out.println("Please only use digits to make a selection.");
response(maxValue);
}
}
return yesOrNo; //returns the user's response. Well, it is supposed to.
}
I am a beginner with regards to programming. I am learning Java through online tutorials and trial and error on dumb, little programs I make. I am working on a fun little text-adventure and am still in the beginning stages.
The trouble I'm having is because this method will only return 0. Isn't yesOrNo being assigned the integer that the user inputs through the scanner response? Why is it only returning 0?
Thank you for your responses. I understand now that I needed to declare my int yesOrNo outside of the try because it was out of scope, as you all put it, being declared within.
BUT a few mentioned 'there is a completely unnecessary function call in the catch block'. The only problem is if I remove it there is an infinite loop created with the System.out.println("Please only use digits to make your selection.") when the user inputs Strings or other non-int values.
Here is my updated code:
//This method handles the players input and checks if the number entered is one of the options listed or not
public static int response(int maxValue){ //the parameter is the number of options in the particular list
response = new Scanner(System.in);
Boolean check = true;
int yesOrNo = 0;
while(check){
try{
yesOrNo = response.nextInt();
if(yesOrNo > maxValue || yesOrNo <= 0){ //checks if the int entered does not exceed the list size or go below zero
System.out.println("I'm sorry, that number was not one of the options. Please reselect your choice.");
}else{
check = false;
}
}catch(Exception e){ //catches an exception when the user enters a string or anything but an int
System.out.println("Please only use digits to make a selection.");
response(maxValue);
}
}
return yesOrNo; //returns the user's response. Well, it is supposed to.
}
After reading other post before just asking another question I found many others facing the same issue. It was correct what some were saying that the infinite loop was created because when the Scanner encounters an error it doesn't remove the token of that error thus causing the while loop to read the same error over again infinitely. Here is what i read exactly:
"As per the javadoc for Scanner:
'When a scanner throws an InputMismatchException, the scanner will not pass the token that caused the exception, so that it may be retrieved or skipped via some other method.'
That means that if the next token is not an int, it throws the InputMismatchException, but the token stays there. So on the next iteration of the loop, getAnswer.nextInt() reads the same token again and throws the exception again. What you need is to use it up. Add a getAnswer.next() inside your catch to consume the token, which is invalid and needs to be discarded."
So now that infinite loop problem is fixed :) Onto finding what else I need to learn. Thank you.
yesOrNo goes out of scope because you declared it within the try block. Move the declaration outside to where it is in scope when you return it.
Boolean check = true;
int yesOrNo;
yesOrNo you're returning is not same as
int yesOrNo = response.nextInt();
in your loop. The yesOrNo from the loop disappears (goes out of scope) at the closing } of try.
There has to be another int yesOrNo somewhere. Look for it.
The only this can compile is if yesOrNo is declared as a class or instance variable, unseen in this code snippet.
The declaration of yesOrNo that we do see is declared inside a try block, shadowing the yesOrNo being returned. But there's no reason for it to be a class or instance variable.
Remove it from the class declaration, and declare it locally, before the try block, so it's in scope when it's returned.
int yesOrNo = 0;
try{
yesOrNo = response.nextInt();
I see "int yesOrNo" inside while loop. The value read inside while loop scope is limited to that. Declare that variable outside and try.
Eclipse says that the variable age, agirl and aboy may not have been initialized. I initialized the variables before the first if statement and they got values in the if-statement. When I want to use them in the next if-statement eclipse says the local variables may not have been initialized.
Here is my code:
import java.util.Scanner;
class Main{
public static void main(String args[]){
Scanner input = new Scanner(System.in);
String define;
int aboy, agirl, age;
System.out.println("Are you a boy or a girl?");
define = input.next();
if (define.equals("boy")){
System.out.println("What is your age?");
aboy = input.nextInt();
age = aboy;
}else if (define.equals ("girl")){
System.out.println("What is your age?");
agirl = input.nextInt();
age = agirl;
}else
System.out.println("wrong answer");
if (agirl >= 18 || aboy >= 16){
System.out.println("You are a " + define + " and you are " + age + " years old");
}
}
}
This line
int aboy, agirl, age;
contains declarations, not initializations. Java will not initialize a local variable for you, and there is an execution path (the else) where nothing is ever assigned to those variables, then you attempt to reference their nonexistent values.
You must set values to them before you use them, in all execution paths. Initialize them to something when you declare them.
Not only may you have an uninitialized variable, you're guaranteed to.
Look at your control flow: You first ask for a value for define, and then you execute exactly one of the blocks. If define is "boy", you don't initialize agirl; if define is "girl", you don't initialize aboy, and if define doesn't match either, you don't initialize any of your variables at all.
It looks like you are trying to cleverly combine the functions of a boolean and an int by having "magic" values in your ints. This is poor design because it's not clear how the magic works, but you can make your example run by initializing all of your int values to 0:
int aboy = 0, agirl = 0, age = 0;
Initializing is assigning the variable a value. Declaring is creating the variable. They are not the same.
The reason you need to initialize the variables is because it is possible they will not be initialized. All the if statements could be false, thus you need to give them a default value.
(First of all, I apologize if this is a basic question, but I'm new to coding)
What i want to do is to verify whether a string as a certain combination of characters and then replace them using an if-else statement, like this:
String RAWUserInput = sometextfield.getText().toString();
if (RAWUserInput.contains("example") {
String UserInput = RAWUserInput.replace("example", "eg");
}else{
String UserInput = RAWUserInput;}
sometextbox.setText(UserInput);
and then access the string outside of the if-else statement. I don't know how to do the last line because java can't find the string, What should I do?
Thanks in advance :)
Declare the variable before the if statement.
String UserInput;
if (RAWUserInput.contains("example") {
UserInput = RAWUserInput.replace("example", "eg");
}else{
UserInput = RAWUserInput;
}
It will remain in scope after the if statement. If the variable is declared inside the if block or else block (in between the braces), then it goes out of scope after the end of the block.
Also, the compiler is smart enough to determine that something is always assigned to UserInput in every case, so you won't get a compiler error that the variable may not have been assigned a value.
In Java, variables are typically named starting with a lowercase letter, unlike classes. Normally, your variables would be named userInput and rawUserInput.
When you declare a variable inside a block ({ ... }), the variable only exists inside that block.
You need to declare it outside the block, then assign it inside the blocks.
String rawUserInput = sometextfield.getText().toString();
String userInput = ""; // empty
if (rawUserInput.contains("example") {
userInput = rawUserInput.replace("example", "eg");
} else{
userInput = rawUserInput;
}
sometextbox.setText(userInput);
Otherwise, save the else statement:
String rawUserInput = sometextfield.getText().toString();
String userInput = new String(rawUserInput); // copy rawUserInput, using just = would copy its reference (e.g. creating an alias rawUserInput for the same object in memory)
if (rawUserInput.contains("example") {
userInput = rawUserInput.replace("example", "eg");
}
// no else here
Also, have a look at coding guidelines: indenting your code makes it more readable, starting temporary variable names with a lowercase is preferred.
String UserInput = RAWUserInput.contains("example")? RAWUserInput.replace("example", "eg"): RAWUserInput;