Java variable initialization different ways of handling? - java

I just found that Java handles variable initialization in different ways.
Case-1:
class A {
boolean x;
public static void main(String[] args) {
A a = new A();
System.out.println(a.x);
}
}
When I ran above program it shows like "false" as output. But now I am posting other piece of code:
Case-2:
class A {
public static void main(String[] args) {
boolean x;
System.out.println(x);
}
}
Now, above piece of code shows that
java.lang.Error: Unresolved compilation problem:
The local variable x may not have been initialized
Why the same thing is handled in very different ways?
Thanks in advance!

From the Oracle documentation on Java Primitive Data Types:
Local variables are slightly different; the compiler never assigns a
default value to an uninitialized local variable. If you cannot
initialize your local variable where it is declared, make sure to
assign it a value before you attempt to use it. Accessing an
uninitialized local variable will result in a compile-time error.
So this is an interesting nuance. If a primitive type variable is locally declared, you must specify a value for it.

There are three distinct types of variables:
static variables - within class;
member variables - within object
local variables - having scope limited to a function or block of code
Assumming the variables are not final.
The first two default to 0 or false (when var is a primitive) or
null (when var is an object) when accessed for read. The last one must be set to a value prior to reading, otherwise the code will not compile.
All of variable types (local, member, static) must be assigned a particular value if defined as final. Such Initialisation of static final variable can be an inline assignment to a value or it can be done in static initialisation block. Initialisation of final member variables can be done inline, within Initialisation block or within object's constructor (most common - best practice).
Final local variables initialized inline. There is also "effectively final" variable that is inferred by compiler when it sees that variable will not be changed. Final variables allow compiler to treat and optimize handling of data.
Thats just a couple of basic items to start with. Hope it is helpful.
Cheers.

If this question is about why local variables are treated different from non-final member variables: in the example above I do not see any use do declare boolean x; instead of boolean x = false;, but the last one makes the intent of the programmer clear. Also you are allowed to declare boolean x; if you initialize x later. Here the compiler error you get is helpful so you don't forget to initialize it in some rare edge case. The compiler couldn't check that if it would be initialized by default.
It's also common to have code like
int i;
if (a > b)
i = 8; // loong code
else
i = 42; // loong code
Initializing i would be useless here.
Static and non-static members (non final) are different because the compiler always nulls all fields before running initializers and constructors. Not initializing them to 0 manually is a slight performance improvement.

Explanation
Your two examples use different kinds of variables:
a field (also called instance variable, or member)
a local variable
You can only use a variable if it has a value / refers to an instance. For fields, if you do not explicitly assign a value, they are defaulted. That is not the case for local variables, thus the error.
The default value is null for objects and special values for primitives, like 0, 0.0, false and similar.
Java Language Specification
The JLS clearly defines this behavior and explains how it works. Take a look at chapter 4.12.5 Initial Values of Variables where it states (relevant excerpts):
Every variable in a program must have a value before its value is used:
Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2):
For type boolean, the default value is false.
A local variable (§14.4, §14.14) must be explicitly given a value before it is used, by either initialization (§14.4) or assignment (§15.26), in a way that can be verified using the rules for definite assignment (§16 (Definite Assignment)).

Related

Java - Class fields (Member Variables) can be used in inner class or lambda expressions but not local variables [duplicate]

In a lambda, local variables need to be final, but instance variables don't. Why so?
The fundamental difference between a field and a local variable is that the local variable is copied when JVM creates a lambda instance. On the other hand, fields can be changed freely, because the changes to them are propagated to the outside class instance as well (their scope is the whole outside class, as Boris pointed out below).
The easiest way of thinking about anonymous classes, closures and labmdas is from the variable scope perspective; imagine a copy constructor added for all local variables you pass to a closure.
In a document of project lambda, State of the Lambda v4, under Section 7. Variable capture, it is mentioned that:
It is our intent to prohibit capture of mutable local variables. The
reason is that idioms like this:
int sum = 0;
list.forEach(e -> { sum += e.size(); });
are fundamentally serial; it is quite difficult to write lambda bodies
like this that do not have race conditions. Unless we are willing to
enforce—preferably at compile time—that such a function cannot escape
its capturing thread, this feature may well cause more trouble than it
solves.
Another thing to note here is, local variables are passed in the constructor of an inner class when you access them inside your inner class, and this won't work with non-final variable because value of non-final variables can be changed after construction.
While in case of an instance variable, the compiler passes a reference of the object and object reference will be used to access instance variables. So, it is not required in case of instance variables.
PS : It is worth mentioning that anonymous classes can access only final local variables (in Java SE 7), while in Java SE 8 you can access effectively final variables also inside lambda as well as inner classes.
In Java 8 in Action book, this situation is explained as:
You may be asking yourself why local variables have these restrictions.
First, there’s a key
difference in how instance and local variables are implemented behind the scenes. Instance
variables are stored on the heap, whereas local variables live on the stack. If a lambda could
access the local variable directly and the lambda were used in a thread, then the thread using the
lambda could try to access the variable after the thread that allocated the variable had
deallocated it. Hence, Java implements access to a free local variable as access to a copy of it
rather than access to the original variable. This makes no difference if the local variable is
assigned to only once—hence the restriction.
Second, this restriction also discourages typical imperative programming patterns (which, as we
explain in later chapters, prevent easy parallelization) that mutate an outer variable.
Because instance variables are always accessed through a field access operation on a reference to some object, i.e. some_expression.instance_variable. Even when you don't explicitly access it through dot notation, like instance_variable, it is implicitly treated as this.instance_variable (or if you're in an inner class accessing an outer class's instance variable, OuterClass.this.instance_variable, which is under the hood this.<hidden reference to outer this>.instance_variable).
Thus an instance variable is never directly accessed, and the real "variable" you're directly accessing is this (which is "effectively final" since it is not assignable), or a variable at the beginning of some other expression.
Putting up some concepts for future visitors:
Basically it all boils down to the point that compiler should be able to deterministically tell that lambda expression body is not working on a stale copy of the variables.
In case of local variables, compiler has no way to be sure that lambda expression body is not working on a stale copy of the variable unless that variable is final or effectively final, so local variables should be either final or effectively final.
Now, in case of instance fields, when you access an instance field inside the lambda expression then compiler will append a this to that variable access (if you have not done it explicitly) and since this is effectively final so compiler is sure that lambda expression body will always have the latest copy of the variable (please note that multi-threading is out of scope right now for this discussion). So, in case instance fields, compiler can tell that lambda body has latest copy of instance variable so instance variables need not to be final or effectively final. Please refer below screen shot from an Oracle slide:
Also, please note that if you are accessing an instance field in lambda expression and that is getting executed in multi-threaded environment then you could potentially run in problem.
It seems like you are asking about variables that you can reference from a lambda body.
From the JLS §15.27.2
Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.
So you don't need to declare variables as final you just need to make sure that they are "effectively final". This is the same rule as applies to anonymous classes.
Within Lambda expressions you can use effectively final variables from the surrounding scope.
Effectively means that it is not mandatory to declare variable final but make sure you do not change its state within the lambda expresssion.
You can also use this within closures and using "this" means the enclosing object but not the lambda itself as closures are anonymous functions and they do not have class associated with them.
So when you use any field (let say private Integer i;)from the enclosing class which is not declared final and not effectively final it will still work as the compiler makes the trick on your behalf and insert "this" (this.i).
private Integer i = 0;
public void process(){
Consumer<Integer> c = (i)-> System.out.println(++this.i);
c.accept(i);
}
Here is a code example, as I didn't expect this either, I expected to be unable to modify anything outside my lambda
public class LambdaNonFinalExample {
static boolean odd = false;
public static void main(String[] args) throws Exception {
//boolean odd = false; - If declared inside the method then I get the expected "Effectively Final" compile error
runLambda(() -> odd = true);
System.out.println("Odd=" + odd);
}
public static void runLambda(Callable c) throws Exception {
c.call();
}
}
Output:
Odd=true
YES, you can change the member variables of the instance but you CANNOT change the instance itself just like when you handle variables.
Something like this as mentioned:
class Car {
public String name;
}
public void testLocal() {
int theLocal = 6;
Car bmw = new Car();
bmw.name = "BMW";
Stream.iterate(0, i -> i + 2).limit(2)
.forEach(i -> {
// bmw = new Car(); // LINE - 1;
bmw.name = "BMW NEW"; // LINE - 2;
System.out.println("Testing local variables: " + (theLocal + i));
});
// have to comment this to ensure it's `effectively final`;
// theLocal = 2;
}
The basic principle to restrict the local variables is about data and computation validity
If the lambda, evaluated by the second thread, were given the ability to mutate local variables. Even the ability to read the value of mutable local variables from a different thread would introduce the necessity for synchronization or the use of volatile in order to avoid reading stale data.
But as we know the principal purpose of the lambdas
Amongst the different reasons for this, the most pressing one for the Java platform is that they make it easier to distribute processing of collections over multiple threads.
Quite unlike local variables, local instance can be mutated, because it's shared globally. We can understand this better via the heap and stack difference:
Whenever an object is created, it’s always stored in the Heap space and stack memory contains the reference to it. Stack memory only contains local primitive variables and reference variables to objects in heap space.
So to sum up, there are two points I think really matter:
It's really hard to make the instance effectively final, which might cause lots of senseless burden (just imagine the deep-nested class);
the instance itself is already globally shared and lambda is also shareable among threads, so they can work together properly since we know we're handling the mutation and want to pass this mutation around;
Balance point here is clear: if you know what you are doing, you can do it easily but if not then the default restriction will help to avoid insidious bugs.
P.S. If the synchronization required in instance mutation, you can use directly the stream reduction methods or if there is dependency issue in instance mutation, you still can use thenApply or thenCompose in Function while mapping or methods similar.
First, there is a key difference in how local and instance variables are implemented behind the scenes. Instance variables are stored in the heap, whereas local variables stored in the stack.
If the lambda could access the local variable directly and the lambda was used in a thread, then the thread using the lambda could try to access the variable after the thread that allocated the variable had deallocated it.
In short: to ensure another thread does not override the original value, it is better to provide access to the copy variable rather than the original one.

Blank Final Local vs Blank Final Field

Why does not initializing a local final variable compile? This behavior seems to contrast final fields where not initializing a gives a compilation error.
class Test {
final Test test1; // doesn't compile
public Test(){
final Test test2; // does compile
}
}
What's the logic behind this choice?
This comes from the rules of the JLS.
From 4.12.4
It is a compile-time error if a final variable is assigned to unless it is definitely unassigned (§16) immediately prior to the assignment.
From 4.12.5
A local variable (§14.4, §14.14) must be explicitly given a value before it is used, by either initialization (§14.4) or assignment (§15.26), in a way that can be verified using the rules for definite assignment (§16).
From 8.3.1.2
A blank final instance variable must be definitely assigned (§16.9) at the end of every constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs.
So the technical reason why that works is because it's not forbidden. Fields must be initialized by the time the object is constructed. Local variables only need to be initialized before they're used.
The logic behind it is that a class variable might be referenced from another object, so it needs to be initialized by the time that another object might have an initialized reference to it. A local variable doesn't escape it's scope though, so the compiler can guarantee that it's not referenced as long as it's not used within that scope.

Why can you have a duplicate variable name in java for a variable outside of a method?

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.

Instance and Constant variables

I was wondering is a variable could be both instance and constant? For example would
private final int Min=25;
be both an instance variable and a constant variable?
The Java Language Specification has a chapter on variables.
A variable is a storage location and has an associated type, sometimes
called its compile-time type, that is either a primitive type (§4.2)
or a reference type (§4.3).
There are different types of variables: class, instance, local, method parameter, exception parameter in catch block, constructor parameter, and array components.
There are also final variables which can only be assigned once.
If you declare a non-static field in a class, that is considered an instance variable.
The JLS also says
A variable of primitive type or type String, that is final and
initialized with a compile-time constant expression (§15.28), is
called a constant variable.
So yes, yours is both an instance and constant variable.
From Chapter 4 of the Java Language Specification
In section 4.12.3
An instance variable is a field declared within a class declaration without using the keyword static
In section 4.12.4
A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.
So, yes, this is both a constant variable and an instance variable.
Feel free to use the term "constant variable". It sounds oxymoronic, but the JLS uses it, so you are fine to do so.
Yes, your example would be both an instance and a constant.
There are reasons for having an instance variable that can't be changed.
One is having clear and easy to read code. When you see a variable as final early on, you dont have to worry later on in the program if it is changing value or reference. This allows you to focus on other parts of the program where variables actually are changing.
Take a look at JLS for more info on variables
Instance Variable : an instance variable is a variable defined in a class (i.e. a member variable), for which each object of the class has a separate copy, or instance.
For example :
class MyClass {
int a; // instance variable;
People p; // instance variable;
static int b; // not instance variable. because all instances of class MyClass use same variable b
static People community; // not instance variable with same reason.
}
Constant : a constant is an identifier whose associated value cannot typically be altered by the program during its execution. In Java, there isn't no real constant as C#. In C#, you declare constant is :
// C# Code
const int a = 3; // true
const int a; // wrong. because constant must permently have value. because it cannot have another values in their life.
But in Java, there is just : a variable that you can initialize only one time. and you use it final :
// Java Code
final int a = 3; // true
final int b; // still true. you can declare it later
So. combine above knowledge, you can say your example : private final int Min=25; is both instance variable and "const" variable (java doesn't have const variable, remember)
Hope this help :)
An instance variable is a variable that every instance of a class is going to have its own version of. For example, if you have a Car class, an instance variable of Car might be color. Each time you make a new instance of Car, you can set its color instance variable.
A constant just means that it is unable to change after assignment -- it must also be initialised with a constant expression (thanks David!). So for the Car class, you could instantiate a new Car object with a specific color instance variable. In the Car class code, you could use the final keyword to make the color unchanging after it is set.
Yes, an instance variable can be defined as a constant.

Java Constructors- Assigning value to variable

Is there a difference between assigning values to variables outside of any method, and assigning these values within a constructor?
Looking at Oracle's Java tutorial, they have:
public class Bicycle {
int cadence = 0;
int speed = 0;
int gear = 1;
void changeCadence(int newValue) {
cadence = newValue;
}
is this any different from saying/why didn't they just say:
Bicycle(){
int cadence = 0;
}
If you declare the variable in your constructor, it will be local to the constructor and not visible anywhere else in your class.
If you declare a variable inside a constructor, this variable can only be accessed inside this constructor. But, you can create a variable on your class, and access it on your constructor or method.
Well if you define a variable in a constructor, it is local to the constructor. But a variable in the class is part of class' state.
But if you mean:
class A {
int i = 1;
...
}
vs
class B {
int i;
B() {
i = 1;
}
...
}
the difference is: in the first case, the default value of i is 1, in all instances, but in second case the default value of i is 1 if the shown constructor is called, maybe in other constructors other default value be something else (or 0 if nothing is assigned to i).
When you create object instance, global variables will be initialized. You can (but not have to) change some of them in constructor.
I think you mean
Bicycle() {
cadence = 0;
}
In the constructor : it will be Local variable
Java contains the following types of variables:
Instance Variables (Non-static fields): In object oriented programming, objects store their individual states in the "non-static fields" that is declared without the static keyword. Each object of the class has its own set of values for these non-static variables so we can say that these are related to objects (instances of the class).Hence these variables are also known as instance variables. These variables take default values if not initialized.
Class Variables (Static fields): These are collectively related to a class and none of the object can claim them its sole-proprietor . The variables defined with static keyword are shared by all objects. Here Objects do not store an individual value but they are forced to share it among themselves. These variables are declared as "static fields" using the static keyword. Always the same set of values is shared among different objects of the same class. So these variables are like global variables which are same for all objects of the class. These variables take default values if not initialized.
Local Variables: The variables defined in a method or block of code is called local variables. These variables can be accessed within a method or block of code only. These variables don't take default values if not initialized. These values are required to be initialized before using them.
Parameters: Parameters or arguments are variables used in method declarations.
The constructor is like any other method. Variables that are declared inside it are available only within it, and they'll get destroyed when you go out of scope.
The difference in this case is that you are not only assigning the variable in the constructor (in the second case). You are also declaring it there. Thus, the variable is local to the constructor and not visible from outside.
I think your question is: If we can give a default value to the variable(of a class) directly, why to give it inside a constructor instead. If that's the question, then I think its because the values in the variable would be available even when the objects are not initialized which is not a healthy practice and does not make much sense. Instead, giving values inside a constructor would not only be hidden but would also obey oops rules for java.

Categories

Resources