How to access variable that is in the while loop from outside it ?
Always declare variables at the scope that makes sense. If your variable is to be referenced both inside and outside a loop, then it must be declared outside the loop.
public String doIt() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 100; i++) {
builder.append("ponies ");
}
return builder.toString();
}
It is good practice to narrow the scope of variables so that they are only visible where they are needed.
a) don't. it's a bad idea
b)
Define it outside the loop
int x;
while(something){
x = somethingElse;
}
Declare the variable outside the loop.
Related
I got this situation I can't understand about shadowing. For example the following code:
class Foo {
int a = 5;
void goFoo(int a) {
// No problem naming parameter as same as instance variable
for (int a = 0; a < 5; a++) { }
// Now the compiler complains about the variable a on the for loop
// I thought that the loop block had its own scope so I could shadow
// the parameter, why the compiler didn't throw an error when i named
// the parameter same as the instance variable?
}
}
You can make a local variable shadow an instance/static variable - but you can't make one local variable (your loop counter) shadow another local variable or parameter (your parameter).
From the Java Language Specification, section 14.4.3:
If a name declared as a local variable is already declared as a field name, then that outer declaration is shadowed (§6.3.1) throughout the scope of the local variable.
Note the "field name" part - it's specifying that it has to be a field that is shadowed.
And from section 8.4.1:
The scope of a parameter of a method (§8.4.1) or constructor (§8.8.1) is the entire body of the method or constructor.
These parameter names may not be redeclared as local variables of the method, or as exception parameters of catch clauses in a try statement of the method or constructor.
(It goes on to talk about local classes and anonymous classes, but they're irrelevant in your case.)
void goFoo(int a) {
for (int a = 0; a < 5; a++) { }
}
it is similar to
void goFoo() {
int a;
for (int a = 0; a < 5; a++) { }
}
so multiple declaration of a on the same scope, it is not acceptable.
or simply it is similar to
void goFoo() {
int a;
int a;
}
Also See
java-variable-scope-shadowing
The scope of the variable depends on the hierarchy of the block as well.
ie if u use like this
void goFoo(int a) {
// No problem naming parameter as same as instance variable
for (int b = 0; b < 5; b++) { }
//Now the compiler complains about the variable a on the for loop
// i thought that the loop block had its own scope so i could shadow
// the parameter, why the compiler didnt throw an error when i named
// the parameter same as the instance variable?
int b; // you can do this.
}
That is if a variable is declared in the outer block then you can not declare the same in the block which is inner. the other way you can do it.
But you don't declare the second "a" in that new scope, as your code shows. It's in the scope of the goFoo() block itself.
The problem isn't that the loop is shadowing the class field, the name is already used by the parameter.
Two options: One is to change the loop:
for (a = 0; a < 5; a++) { }
This uses the parameter as the index variable. Not clear why you would have a parameter, but all the same...
The other option is to rename the loop variable or the parameter to something else.
It is not shadowing, it is a conflict here. Both a are in the method scope. One cannot define two variables of same name in the same scope.
In Java (unlike, say, in c++) you cannot declare a local variable when another local variable with the same name is "in scope".
You cannot do this in Java
void foo() {
int a;
{
int a; // You cannot declare 'a' here because a
// from the outer block is still in scope
// here. Local variables in Java cannot be
// shadowed by another local variable with
// the same name. Only instance variables
// can be shadowed by the local variables
// with the same name.
}
}
However c++ allows you to do this
void foo()
{
int a;
a = 10;
cout << a << endl; // prints 10 duh
{
int a; // this declaration shadows the local
// variable 'a' from the outer scope.
a = 20; // assigns 20 to the variable 'a' in
// current inner scope, like you'd expect.
cout << a << endl; // prints 20.
}
cout << a << endl; // prints 10
}
class Myclass {
public static void main(String[] args) {
int x; // Declared in main method
if (true) {
for (int i = 0; i < 5; i++) {
x = 5;// initialized inside loop
}
}
System.out.println(x);// accessing outside for loop
}
}
This gives an error: variable x might not have been initialized
System.out.println(x);
^
1 error;
However, below code working fine
class Myclass {
public static void main(String[] args) {
int x; // Declared in main method
if (true) {
x = 5;// initialized in if block
for (int i = 0; i < 5; i++) {
// x=5;
}
}
System.out.println(x);// accessing outside if loop
}
}
Here in both the code, the only difference is that in 1st case, the variable is initialized in "for loop" while in 2nd case it is initialized in "if block". then why it is making difference. Kindly explain to me as I am not able to find the real reason.
The problem is that the compiler doesn't know thatx will be initialized when you access it. That's because the compiler doesn't check whether the loop body will actually be executed (there might be rare cases where even such a simple loop might not run).
The same would be true for your if-block if the condition wouldn't be always true, i.e. if you'd use a boolean variable like this:
int x;
boolean cond = true;
if( cond ) {
x = 5;
}
//The compiler will complain here as well, as it is not guaranteed that "x = 5" will run
System.out.println(x);
You as a human would say "but cond is initialized to true and will never change" but the compiler doesn't know for sure (e.g. because of possible threading issues) and thus it will complain. If you'd make cond a final variable then the compiler would know that cond would not be allowed to change after initialization and thus the compiler can inline the code to effectively have if(true) again.
In this code:
public static void main (String[] args)
{
int x; // Declared in main method
if(true)
{
for(int i=0;i<5;i++)
{
x=5;// initialized inside loop
}
}
System.out.println(x);//accessing outside for loop
}
x will only be set if the loop runs. The compiler considers it a possibility that that will never happen.
In the other case: if(true) the compiler recognizes as "This will happen"
If you want to avoid this, change
int x;
to
int x = 0; // or use another default variable
It is accessible still there is a chance that the program will never access the for block. Since compiler does not meet any other initialization of the var outside the for loop it gives you an error. In order to compile it you have to initialize the variable with a default value :
class Myclass {
public static void main (String[] args) {
int x = 0; // Declared in main method and init with a default value.
if(true) {
for(int i=0;i<5;i++) {
x=5;// Reinitialized inside loop
}
}
System.out.println(x); // No problems here.
}
}
In java for loop evaluated at run-time so compiler ignores check for variable initialization inside loop, that is the reason "x" have to initialized with value.
If you change the condition in the if block from true to false you would get the same error that variable 'x' might not have been initialized. When you do if(true) the compiler can understand that the code inside if block will always run and hence the variable x would always be initialized.
But when you initialize the variable inside the for loop, it may happen that the for loop is never run and variable is left uninitialized.
public static void main(String[] args) {
int x; // Declared in main method
if(false)
{
x=5; //compile error
for(int i=0;i<5;i++)
{
//x=5 initialized inside loop
}
}
System.out.println(x);
}
To avoid this scenario initialize the variable as int x = 0;
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to get a list of the longest words from each line in a block of text. I cant get the information to print from my main which is in processing.class. The information is processed in Tools.class. and there is also a Counters.class that is involved but it is immutable.
However, it gives me this warning: The value of the local variable longestWords is not used in my counter code, on the line where i declare longestWords =h;. Why is this, and how can I fix it?
This is my code:
(Processing)
longestWords = stat.getLongestWords();
for(i = 0; i < longestWords.size(); i++){
System.out.print(longestWords.get(i));
}
Error thrown: Exception in thread "main" java.lang.NullPointerException
at deol5210_a1.Processing.main(Processing.java:66)
which points to for(i = 0; i < longestWords.size(); i++){
(Tools)
}else {
currentWord = lineScanner.next();
if(currentWord.contains("$")){
currentWord.replace("$", "");
moneySpent += Double.parseDouble(currentWord.replace("$", ""));
}else if (currentWord.length() > lineLongestWord.length()){
lineLongestWord = currentWord;
}
if(currentWord.length() > longestWord.length()){
longestWord = currentWord;
lineLongestWord = currentWord;
wordCount++;
} else {
wordCount++;
}
(Counters)
public ArrayList<String> getLongestWords(){
return longestWords;
}
public Counters(int a, double b, int c, int d, double e, double f, String g, ArrayList<String> h){
lineCount = a;
avgWordCount = b;
wordCount = c;
purchaseCount = d;
moneySpent = e;
avgSpent = f;
longestWord = g;
ArrayList<String> longestWords = h;
}
Initializing a variable is different from using it, the warning will disappear when you use the variable (print it, pass it to a method, etc').
Basically it's the same as saying:
int i = 0;
and then not doing anything with i.
The statement
ArrayList<String> longestWords = h;
creates a new local variable longestWords and then does nothing with it, if you have a member called longestWords the statementshould be simply:
longestWords = h;
Another criticism, you never declare the variable i, but you try to assign it to a value. You need to change the following:
for(i = 0; i < longestWords.size(); i++)
to
for(int i = 0; i < longestWords.size(); i++)
As for your warning, you are declaring longestWords within the block scope of your Counters constructor. This is most likely supposed to be an instance variable within Counters, not a private variable within the constructor.
Get rid of the declaration there, and instead use the variable that is most likely already defined in your class. From:
ArrayList<String> longestWords = h;
to
longestWords = h;
Java variables have something called "scope". A variable declared inside a method, like your longestWords variable, is a local variable. Its scope is restricted to that method. That means that outside of that method, the definition of longestWords as it is declared in the method does not exist. You are trying to access a local variable from outside the method in which it was declared. By definition, a local variable does not exist outside of the method in which it is declared.
If you want to use a variable in multiple methods, you need to declare it outside of any methods, making it a global variable.
If there is ever a local variable that is declared with the same name as a global variable, that variable name will refer to the local variable within the method, and to the global variable outside the method (because the local variable doesn't exist outside the method in which it was declared). So if you initialize that variable inside the method, it will not affect the value of the global variable.
I am not understanding the concept of final variable. In a for loop I have dynamic variable i which is crucial for me to refer an array. As soon as I use i, it throws me an error saying it should be final.
What exactly is final? Could you please help to get rid of that error?
My code is here:
for( int i = 0; i <4; i++)
{
Bitmap celeb1=Bitmap.getBitmapResource(fimagearray[i]);
Bitmap celeb1_focus=Bitmap.getBitmapResource(fimagearray[i]);
ImageButton celebbutton = new ImageButton(celeb1, celeb1_focus);
celebbutton.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context)
{
UiApplication.getUiApplication().pushScreen(new FetchTweets(fusernamearray[i]));
}
});
femaleSec.add(celebbutton);
}
An anonymous inner class can only access final variables from the outer scope. Since i is not final, it can't be accessed directly. You can't make i final since it needs to change, and a final variable can't be changed.
As a simple workaround, copy the value of i into a final variable during each loop iteration:
for( int i = 0; i < 4; i++)
{
final int index = i; // <-- copy i to `index' to use in FieldChangeListener
// ...
celebbutton.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context)
{
UiApplication.getUiApplication().pushScreen(
new FetchTweets(fusernamearray[index])); // <-- `index'
}
});
femaleSec.add(celebbutton);
}
A final variable can only be initialized once, either via an initializer or an assignment statement
Check out the this link for it.
Also Look at this Example.
You are attempting to use the value of i inside of an 'Anonymous Inner Class' which requires that all non-local variables to that class be declared as final, meaning that the variable's value may not be changed once it has been initialized.
The solution posted by #aix would solve your problem.
This question already has answers here:
Why does Java not have block-scoped variable declarations?
(6 answers)
Closed 5 years ago.
I know in C++ variables have block scope, for example, the following code works in C++:
void foo(){
int a = 0;
for (int i = 0; i < 10; ++i){
int a = 1; // Redefine a here.
}
}
But this snippet doesn't work in Java, it reports "duplicate local variable a", does it mean Java variables don't have BLOCK scope?
They have block scope. That means that you can't use them outside of the block. However Java disallows hiding a name in the outer block by a name in the inner one.
java variables do have a block scope but if you notice int a is already defined in scope
{
int a = 0;
{
{
}
}
}
all subscopes are in scope of the uppermost curly braces. Hence you get a duplicate variable error.
Section §14.4.2 says:
The scope of a local variable
declaration in a block (§14.2) is the
rest of the block in which the
declaration appears, starting with its
own initializer (§14.4) and including
any further declarators to the right
in the local variable declaration
statement.
The name of a local variable v may not
be redeclared as a local variable of
the directly enclosing method,
constructor or initializer block
within the scope of v, or a
compile-time error occurs.
The previous answers already stated the reason, but I just want to show that this is still allowed:
void foo(){
for(int i = 0; i < 10; ++i){
int a = 1;
}
int a = 0;
}
In this case the a inside the loop doesn't hide the outer a, so it's valid.
Also IMHO it should be this way in C++ too, it's less confusing and prevents accidental declaration of variable with same name.
It does, but it's nested, so the "a" you defined in foo() is available in all blocks within foo.
Here is an example of what you're looking for:
void foo(){
{
int a = 0;
// Do something with a
}
for(int i = 0; i < 10; ++i){
int a = 1; //define a here.
}
}