Why is it that curly braces do not define a separate local scope in Java? I was expecting this to be a feature common to the main curly brace languages (C, C++, Java, C#).
class LocalScopeTester
{
public static void main(String... args)
{
Dog mine = new Dog("fido");
if (mine.getName().equals("ace"))
{
Dog mine = new Dog("spot"); // error: duplicate local
}
else
{
Dog mine = new Dog("barkley"); // error: duplicate local
{
Dog mine = new Dog("boy"); // error: duplicate local
}
}
}
}
They do define a separate local scope, but you still cannot mask local variables from a parent scope (but you can of course mask instance variables).
But you can define new variables (with different names) and their scope will be limited to within the braces.
Local variable shadowing is prohibited in Java on purpose (see this answer).
The idea is that this helps decreasing bugs.
The braces do scope the variable but anything inside a brace can also 'see' further up the brace. In all the cases you have, mine is already defined as fido.
To put it more succinctly. The children are scoped to their parents as well but not vice versa.
They do define a separate local scope, just it is an error if a local variable hides another.
Try defining a variable (with a unique name) inside a block, then accessing from outside that block to see that it is indeed scoped to the block, and only that block.
Blocks define a local scope, but don't allow you to redefine a variable with the same name as another variable in an outer local scope. If it did, there would be no way to access the "hidden" variable.
It does define a local scope... the variables declared inside curly braces have the braces' scope. However what you are trying to do is redeclare an already existing variable. In my opinion, it's not Java that's wrong in this case, but C++ for letting you do it (I assume that's what you were comparing it to). Nonetheless, even if the language would allow it, why would you do it? Poor readability right there, and possible cause for bugs.
Run this and you'll get an error that the variable is already declared as int i=5 and one cannot redefine. So, the Parent never takes what its child got.
So, what if the Parent sacrifices and removes his declaration of int i=5?
public class Ouch {
public static void main(String[] args) {
int i=5;
for(int i=0;i<5;i++);
for(int i=0;i<5;i++);
}
}
Now, the Parent sacrificed its declaration and both the children enjoy and the code runs successfully.
public class Ouch {
public static void main(String[] args) {
//int i=5;
for(int i=0;i<5;i++);
for(int i=0;i<5;i++);
}
}
It's forgotten in Java but I think Java is wrong because in ALL "block structured" languages it is authorized to do this (not only in C++ but also in Pascal, ADA, C, and so on...) and sometime we want to hide a variable of the enclosing block.
Related
I am learning Java and I understand that you cannot name a variable declared within an inner scope the same name as a variable declared in an outer scope as shown below
public class Practice {
public static void main(String[] args){
int x = 10;
if (x == 10){
int x = 10;
}
}
}
However, I noticed that the following is not illegal
public class Practice {
int x = 10;
public static void main(String[] args){
int x = 10;
if (x == 10) {
}
}
}
Is this not a variable that is declared twice??
Is this not a variable that is declared twice??
No, it is not. Because they both are in different scope. x outside of main function has class level scope while x inside of main has method/function level scope.
It is legal for 2 variables in different scope to have same name.
Please DO read §6.3. Scope of a Declaration from JLS. Below are few of the statement from that section.
The scope of a declaration is the region of the program within which
the entity declared by the declaration can be referred to using a
simple name, provided it is visible (§6.4.1).
A declaration is said to be in scope at a particular point in a
program if and only if the declaration's scope includes that point.
The scope of a local variable declaration in a block (§14.4) is the
rest of the block in which the declaration appears, starting with its
own initializer and including any further declarators to the right in
the local variable declaration statement.
There are lot of concepts related to scope like shadowing, so do read §6.4. Shadowing and Obscuring.
JLS is the best place to learn what is allowed and what is not allowed in Java. Feel free to read sections there.
In the second case when x is declared outside the method, it is an instance variable of the class Practice. Within the method, scope of x(declared inside main) is limited to the main method.
In the first case when you declare x within the method, you cannot declare it inside if because it is already declared in the scope of the method outside if.
The first code snippets shows the variables are in method's scope. So two variable are belonging to same method which is not allowed.
But in the second example one variable is on instance level and the other one in method's scope, so there is no duplicate. In the second example if you want to access the instance variable, you have to do it using this.x.
Check more on scope and lifetime of variables here
http://www.javawithus.com/tutorial/scope-and-lifetime-of-variables
Why can you have a duplicate variable name in java for a variable outside of a method?
It is not illegal because it is allowed by the Java Language Specification. (Yes ... circular explanation)
As with all such questions, we cannot tell you for sure why it is allowed, because the Java language was designed behind closed doors. However, a couple of possible reasons are:
Java was originally designed to be "palatable" to C and C++ programmers, and this is a case where doing it differently (banning shadowing) would have caused objections.
A lot of people actually like it that they don't have to think of different names for variables; e.g.
public class Foo {
private Bar bar;
public Foo() {
Bar bar = new Bar();
this.bar = bar;
}
}
Admittedly, there is a downside. Sometimes, people mistakenly declare local variables that shadow instance (or static) variables. Particularly newbies :-)
Is this not a variable that is declared twice??
No. It is actually two >>distinct<< variables. Both exist. Within the method, the local declaration of x shadows the instance declaration of x. But you can still refer to the latter as this.x.
I can't think why the captured variables are final or effectively final in lambda expressions. I looked over this question and really quite didn't get the answer.
What is this variable capture?
As I searched solutions for my problem, I read that these variables are final because of concurrency problems. But for such situation why can't we lock the task code in the lambda with a reentrant lock object.
public class Lambda {
private int instance=0;
public void m(int i,String s,Integer integer,Employee employee) {
ActionListener actionListener = (event) -> {
System.out.println(i);
System.out.println(s);
System.out.println(integer);
System.out.println(employee.getI());
this.instance++;
employee.setI(4);
integer++;//error
s="fghj";//error
i++;//error
};
}
}
In this particular code I want know the reasons why the last three statements gives an error, and why do we get to mutate Employee since it's a local variable.(Employee is just a class with getters and setters ofint i.)
Also i like to know why we can mutate this.instance too.
I appreciate a full detailed answer on all facts I mentioned above.
I read that these variables are final because of concurrency problems.
Wrong, this has nothing to do with concurrency, it's all about how lambdas (and anonymous classes) "capture" variable values.
I want know the reasons why the last three statements gives an error
Because they are captures, so they must be effectively final.
You really don't need to know why the internals require this, just accept the fact that you need to adhere to that rule.
i like to know why we can mutate this.instance
Because the code doesn't capture instance, it captures this, and this is implicitly final.
Reason Why
A lambda is mostly syntactic sugar for an anonymous class. That's not really true, but for the purpose of this explanation, it's true enough, and the explanation is easier to understand for an anonymous class.
First understand, there is no such thing as an anonymous class in the JVM. Actually, there is no such thing as a lambda expression either, but that's a different story.
However, since Java (the language) has anonymous classes, but the JVM doesn't, the compiler has to fake it, by converting the anonymous class into an inner class. (FYI: Inner classes don't exist in the JVM either, so the compiler has to fake that too.)
Let's do this by example. Say we have this code:
// As anonymous class
int i = 0;
Runnable run = new Runnable() {
#Override
public void run() {
System.out.println(i);
}
}
// As lambda expression:
int i = 0;
Runnable run = () -> System.out.println(i);
For the anonymous class, the compiler will generate a class like this:
final class Anon_1 implements Runnable {
private final int i;
Anon_1(int i) {
this.i = i;
}
#Override
public void run() {
System.out.println(i);
}
}
and then compile the code to:
int i = 0;
Runnable run = new Anon_1(i);
That's how capture works, by copying the value of the "captured" variable.
The variable isn't captured at all, the value is, because Java is pass-by-value in the constructor call.
Now you can argue, that there is no reason why i should be effectively final. Sure, the local variable i and the field i are now separate, but they could be separately modified.
But there is a reason, and it's a really good reason. The fact that i has been copied, and is separate, is entire hidden, and is an implementation detail. Programmers would constantly forget that, and think they are the same, which would lead to lots of failed code, and many wasted hours of debugging to be reminded of that.
For code clarity, it must be as-if the i local variable was captured, and that the i in the anonymous class is the same as the i outside, because that is what the Java language defines it to be, even though the JVM can't do that.
To make it appear like that, the local variable MUST be effectively final, so the fact that (internally) the variable wasn't captured at all, makes no difference to the running code.
For example
Class Moon{
int a;
void mango()
{
a=9; // put 9 in instance variable "a"
}
void orange()
{
int a; // declare local variable with same name as of instance variable
}
}
How this is possible that we can modify the value of instance variable inside method and also we can declare the local variable with same name as of instance variable?
When there is an instance variable and a local variable you can use the instance variable with this.a and use the local with just a.
Common use:
public void setA(int a) {
this.a = a
}
Modifying instance variables from within methods is:
prescribed by the java language specification, and
pretty much necessary: that's how object-oriented programming works.
(I mean, if you could not modify an instance variable from within a method, then where would you modify it from?)
If you want a particular instance variable to not be modifiable from within methods, then you must mark it with the final keyword, like this: final int a; --you will still be able to initialize it from the constructor.
Declaring a local variable with the same name as an instance variable is perfectly valid java; however, it is not advised, and that's why you can usually configure your IDE to issue a warning when you do that. Actually, if your IDE is not giving you a warning, then this may mean that you are not compiling with enough warnings enabled. Always enable as many warnings as you can.
I am learning Java and I understand that you cannot name a variable declared within an inner scope the same name as a variable declared in an outer scope as shown below
public class Practice {
public static void main(String[] args){
int x = 10;
if (x == 10){
int x = 10;
}
}
}
However, I noticed that the following is not illegal
public class Practice {
int x = 10;
public static void main(String[] args){
int x = 10;
if (x == 10) {
}
}
}
Is this not a variable that is declared twice??
Is this not a variable that is declared twice??
No, it is not. Because they both are in different scope. x outside of main function has class level scope while x inside of main has method/function level scope.
It is legal for 2 variables in different scope to have same name.
Please DO read §6.3. Scope of a Declaration from JLS. Below are few of the statement from that section.
The scope of a declaration is the region of the program within which
the entity declared by the declaration can be referred to using a
simple name, provided it is visible (§6.4.1).
A declaration is said to be in scope at a particular point in a
program if and only if the declaration's scope includes that point.
The scope of a local variable declaration in a block (§14.4) is the
rest of the block in which the declaration appears, starting with its
own initializer and including any further declarators to the right in
the local variable declaration statement.
There are lot of concepts related to scope like shadowing, so do read §6.4. Shadowing and Obscuring.
JLS is the best place to learn what is allowed and what is not allowed in Java. Feel free to read sections there.
In the second case when x is declared outside the method, it is an instance variable of the class Practice. Within the method, scope of x(declared inside main) is limited to the main method.
In the first case when you declare x within the method, you cannot declare it inside if because it is already declared in the scope of the method outside if.
The first code snippets shows the variables are in method's scope. So two variable are belonging to same method which is not allowed.
But in the second example one variable is on instance level and the other one in method's scope, so there is no duplicate. In the second example if you want to access the instance variable, you have to do it using this.x.
Check more on scope and lifetime of variables here
http://www.javawithus.com/tutorial/scope-and-lifetime-of-variables
Why can you have a duplicate variable name in java for a variable outside of a method?
It is not illegal because it is allowed by the Java Language Specification. (Yes ... circular explanation)
As with all such questions, we cannot tell you for sure why it is allowed, because the Java language was designed behind closed doors. However, a couple of possible reasons are:
Java was originally designed to be "palatable" to C and C++ programmers, and this is a case where doing it differently (banning shadowing) would have caused objections.
A lot of people actually like it that they don't have to think of different names for variables; e.g.
public class Foo {
private Bar bar;
public Foo() {
Bar bar = new Bar();
this.bar = bar;
}
}
Admittedly, there is a downside. Sometimes, people mistakenly declare local variables that shadow instance (or static) variables. Particularly newbies :-)
Is this not a variable that is declared twice??
No. It is actually two >>distinct<< variables. Both exist. Within the method, the local declaration of x shadows the instance declaration of x. But you can still refer to the latter as this.x.
I was wondering how to achieve the local static variable in java. I know Java wount support it. But what is the better way to achieve the same? I donot want the other methods in my class to access the variable, but it should retain the value across the invocations of the method.
Can somebody please let me know.
I don't think there is any way to achieve this. Java does not support 'local static' a la C, and there is no way to retrofit this while still keeping your sourcecode "real Java"1.
I donot want the other methods in my class to access the variable, but it should retain the value across the invocations of the method.
The best thing would be to make it an ordinary (private) static, and then just don't access it from other methods. The last bit should be easy ... 'cos you are writing the class.
1 - I suppose you could hack something together that involves preprocessing your code, but that will make all sorts of other things unpleasant. My advice is don't go there: it is not worth the pain.
Rather than trying to actually protect the variable, making the code more obscure and complicated, consider logical protection by comment and placement. I declare normal fields at the start of the class, but a field that should only be accessed from one method just before that method. Include a comment saying it should only be used in the one method:
// i should be used only in f
private int i;
/**
* Documentation for f().
*/
public void f(){
System.out.println(i++);
}
What you want is the ability to constraint intermediate computation results within the relevant method itself. To achieve this, you can refer to the following code example. Suppose you want to maintain a static variable i across multiple calls of m(). Instead of having such a static variable, which is not feasible for Java, you can encapsulate variable i into a field of a class A visible only to m(), create a method f(), and move all your code for m() into f(). You can copy, compile, and run the following code, and see how it works.
public class S {
public void m() {
class A {
int i;
void f() {
System.out.println(i++);
}
}
A a = new A();
a.f();
a.f();
a.f();
}
public static void main(String[] args) {
S s = new S();
s.m();
}
}
In theory, yes - but not in conventional manners.
What I would do to create this:
Create that Object in a totally different class, under the private modifier, with no ability to be accessed directly.
Use a debugging tool, such as the JDI to find that variable in the other class, get it's ObjectReference and manipulate directly or create a new variable which references to that object, and use that variable, which references to the object, in your method.
This is quite complicated, as using the JDI is tough, and you would need to run your program on 2 processes.
If you want to do this, I suggest looking into the JDI, but my honest answer would be to look for another solution.
Based on dacongy's idea of using a method local class I created a simple solution:
public class Main {
public static String m() {
class Statics {
static String staticString;
}
if (Statics.staticString == null)
Statics.staticString = "My lazy static method local variable";
return Statics.staticString;
}
}