What is the scope of a Java variable in a block? [duplicate] - java

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.
}
}

Related

if we declare a variable before a for loop and we are declaring same name variable in for loop statement in java. we are getting error. why? [duplicate]

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
}

Why does encasing variable initialization into an initialization block allow initialization before declaration? [duplicate]

This question already has answers here:
Why can my instance initializer block reference a field before it is declared?
(5 answers)
Closed 4 years ago.
Consider the following code:
class New {
id = 2;
int id = 7;
}
Obviously it won't compile as we attempt to initialize an undeclared variable.
Encasing the statement into an initialization block, however, makes it compile successfully:
class New {
{ id = 2; }
int id = 7;
}
What is this "feature" of an initialization block that makes this initialization before declaration valid?
Before asking the question I read several posts on initialization blocks on SO, but they seem to mostly address issues on the order of initialization (e.g. static vs non-static).
The point is that id = 2; is a statement, which can be put in an initializer block.
Your first code is not illegal because of the declaration order, but because you cannot use statements out of code blocks. This one fails too:
class New {
int id = 7;
id = 2;
}
Declaration of instance variables can appear anywhere in the class. Has nothing to do with initializer blocks at all.
For example, your code is equivalent to
class New {
New() { id = 2; }
int id = 7;
}
According to your question, this would be illegal too, because initialisation happens before declaration.
Just get used to the convention to always declare instance variable on the beginning of the class, if that confuses you.

Why do I get this compiler warning? [closed]

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.

In what order are initializer block and variable definitions and etc. executed? (in java)

I have problem understanding the order in which initialization happens. this is the order I assumed:
*Once per
1. Static variable declaration
2. Static block
*Once per object
3. variable declaration
4. initialization block
5. constructor
but according to this code I am obviously wrong:
class SomethingWrongWithMe
{
{
b=0; //no. no error here.
int a = b; //Error: Cannot reference a field before it is defined.
}
int b = 0;
}
And the error would disappear if I do this:
class SomethingWrongWithMe
{
int b = 0;
{
b=0;
int a = b; //The error is gone.
}
}
I can't figure out why isn't there an error on
b=0;
The Java Language Specification (section 8.3.2.3) says you can use a variable on the left hand side of an expression, i.e. assign to it, before it is declared, but you cannot use it on the right hand side.
All variables are initialized to their default values, then explicit initializers and anonymous blocks are run in the order they are found in the source file. Finally the constructor is called.
Statics are only run once on the first use of a class.
The compile error appears to be a rule of Java rather than something that necessarily makes sense in every case.
Variable definitions are not done "before" blocks. They are both done at the same time, in the order that they are defined
class SomethingWrongWithMe {
{
b = debug("block 1");
}
int b = debug("define");
{
b = debug("block 2");
}
private int debug(String str) {
System.out.println(str);
return 0;
}
}
Output
block 1
define
block 2
First of all, your assumptions are more or less correct, except for the fact that declarations (with initialization, such as int b = 0) and instance initializer blocks are executed in the order they are written.
int b = 0; // executed first
{
b = 1; // executed second
}
int a = b; // executed third
Also note that the declaration i.e. int b is not executed. The declaration just declares the existence of the variable.
As for the error you got (or, rather the error you didn't get) I agree that it looks strange. I assume that the compiler deals with referencing a variable in an expression and assigning a value to it in different ways. When writing to a variable in an instance initializer, it just checks that the variable is there, while when reading from it, it requires it to be declared above the instance initializer block. I'll see if I can find a reference for that in the JLS.

Why does Java not have block-scoped variable declarations?

The following method does not work because the inner block declares a variable of the same name as one in the outer block. Apparently variables belong to the method or class in which they are declared, not to the block in which they are declared, so I therefore can't write a short little temporary block for debugging that happens to push a variable in the outer scope off into shadow just for a moment:
void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
}
Almost every block-scoped language I've ever used supported this, including trivial little languages that I wrote interpreters and compilers for in school. Perl can do this, as can Scheme, and even C. Even PL/SQL supports this!
What's the rationale for this design decision for Java?
Edit: as somebody pointed out, Java does have block-scoping. What's the name for the concept I'm asking about? I wish I could remember more from those language-design classes. :)
Well, strictly speaking, Java does have block-scoped variable declarations; so this is an error:
void methodName() {
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
System.out.println(i); // error
}
Because 'i' doesn't exist outside the for block.
The problem is that Java doesn't allow you to create a variable with the same name of another variable that was declared in an outer block of the same method. As other people have said, supposedly this was done to prevent bugs that are hard to identify.
Because it's not uncommon for writers to do this intentionally and then totally screw it up by forgetting that there are now two variables with the same name. They change the inner variable name, but leave code that uses the variable, which now unintentially uses the previously-shadowed variable. This results in a program that still compiles, but executes buggily.
Similarly, it's not uncommon to accidentally shadow variables and change the program's behavior. Unknowingly shadowing an existing variable can change the program as easily as unshadowing a variable as I mentioned above.
There's so little benefit to allowing this shadowing that they ruled it out as too dangerous. Seriously, just call your new variable something else and the problem goes away.
I believe the rationale is that most of the time, that isn't intentional, it is a programming or logic flaw.
in an example as trivial as yours, its obvious, but in a large block of code, accidentally redeclaring a variable may not be obvious.
ETA: it might also be related to exception handling in java. i thought part of this question was discussed in a question related to why variables declared in a try section were not available in the catch/finally scopes.
It leads to bugs that are hard to spot, I guess. It's similar in C#.
Pascal does not support this, since you have to declare variables above the function body.
The underlying assumption in this question is wrong.
Java does have block-level scope. But it also has a hierarchy of scope, which is why you can reference i within the for loop, but not j outside of the for loop.
public void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
i = j * 2;
}
//this would cause a compilation error!
j++;
}
I can't for the life of me figure out why you would want scoping to behave any other way. It'd be impossible to determine which i you were referring to inside the for loop, and I'd bet chances are 99.999% of the time you want to refer to the i inside the method.
another reason: if this kind of variable declaration were allowed, people would want (need?) a way to access outer block variables. may be something like "outer" keyword would be added:
void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
int i = outer.i * 2;
if(i > 10) {
int i = outer.outer.i * 2 + outer.i;
}
}
}

Categories