List<Integer> = New ArrayList<Integer>
//some other code,make sure that the size of list is bigger than 1
System.out.println(list.get(0).getClass().getName()); // print "System.lang.Integer"
list.get(0) = 1; //this code does't work
Why does list.get(0) = 1 give the following error in IDE(eclipse)?
The left-hand side of an assignment must be a variable.
The type of list.get(0) is Integer, isn't it? Integer test = 1; is correct.
Can somebody explain the difference?
You cannot assign to the result of a method call as if it were an array access expression. The result of the method call list.get(0) is a value, not a variable. This is in contrast to an array access expression, e.g. array[0], which can be treated as a variable and be on the left side of an expression.
The JLS, Section 15.26, backs this up by stating the only things that can be considered a "variable" on the left side of an assignment operator.
The result of the first operand of an assignment operator must be a variable, or a compile-time error occurs.
This operand may be a named variable, such as a local variable or a field of the current object or class, or it may be a computed variable, as can result from a field access (§15.11) or an array access (§15.10.3).
Instead, use the set method.
list.set(0, 1); // index, new value
list.get(0) is not a variable its a constant. So you need to use set() or add function.
Related
Have seen following threads:
Java8 Stream compiler message -- local variable must be final or effectively final
Variable assignment in lambda expression
According to JavaDoc
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.
Any local variable used but not declared in a lambda body must be
definitely assigned (§16 (Definite Assignment)) before the lambda
body, or a compile-time error occurs.
Similar rules on variable use apply in the body of an inner class
(§8.1.3). The restriction to effectively final variables prohibits
access to dynamically-changing local variables, whose capture would
likely introduce concurrency problems. Compared to the final
restriction, it reduces the clerical burden on programmers.
Is arrays an exception to rule 1?
A sample program that validates javadoc:
List<Integer> li = Arrays.asList(1,2,3,45,678);
final int v = 2;
li.stream().filter(e-> e!=v).map(e->e).forEach(System.out::println);
v= 5;
compilation error at line v=5; , obviously
A sample snippet that is violating the final assignment rule:
List<Integer> li = Arrays.asList(1,2,3,45,678);
final int[] v = {2};
li.stream().filter(e-> e!=v[0]).map(e->e).forEach(System.out::println);
v[0]= 5;
Output:
3
45
678
Above snippet is giving no compilation error, am i missing something??
In the first case v is variable of type int, here value of v is 2 and it is final variable. when you try to assign 5 it is giving error because you can't change final variable value(Working as expected).
Comes to second case, v in not a variable of type int, it is an array. In Java arrays are objects, so here v is a reference. Generally a reference refers to an object and contains the address of the object. When your trying to do v[0] = 5 here your changing the value inside the object but not the value of the reference. If you try to do v = new int[1] or v={5} then you will get compilation error
How does this compiles without error? As my understanding, the compiler checks the type of the variable (in this case String), then sees if the type of the expression on the right side corresponds to the variable's type (or at least a subtype but let's stick to the simple case with the String class since it's final).
public class InitClass {
public static void main(String[] args) {
String str = (str = "hello");
System.out.println(str);
}
}
My question is how does str = "hello" compile? Is the compiler already aware that str should be of type String?
When evaluating an assignment expression
First, the left-hand operand is evaluated to produce a variable. If
this evaluation completes abruptly, then the assignment expression
completes abruptly for the same reason; the right-hand operand is not
evaluated and no assignment occurs.
That produces the variable str. Then
Otherwise, the right-hand operand is evaluated. If this evaluation
completes abruptly, then the assignment expression completes abruptly
for the same reason and no assignment occurs.
In your example, the right hand operand is itself another assignment expression. So str, the right hand operand of the assignment operator, is again evaluated to produce a variable, str. Then
Otherwise, the value of the right-hand operand is converted to the
type of the left-hand variable, is subjected to value set conversion
(§5.1.13) to the appropriate standard value set (not an
extended-exponent value set), and the result of the conversion is
stored into the variable.
So "hello" is stored into str. And since
At run time, the result of the assignment expression is the value of
the variable after the assignment has occurred. The result of an
assignment expression is not itself a variable.
the result of the assignment of "hello" to str is the value "hello", that value is again stored in str.
Your case is equivalent to
String str;
str = (str = "hello");
Although the assignments are funny looking, there's nothing wrong conceptually.
Nevertheless, a variable initialization that references itself is obviously not a good idea. The compiler will try to flag it in situations that's very likely a programer error; the compiler fails to do so some times; and may also go overboard some other times.
A local variable has a stricter requirement (than a field variable) - it must be assigned first before its value is used. For example, this won't compile, because the local var is read before it's assigned.
String str; // local variable
str = str; // error, try to read `str` before it's assigned
A field variable always has a default initial value; nevertheless, the compiler checks for apparent programer mistakes
int x = x+1; // error. x is field variable.
But it's not catastrophic if such checking fails, since x has a value 0 before explicit assignment
int x;
{ x=x+1; } // ok. x==0, then x==1 after assignment
However, if x is final, the code above fails, because compiler requires definite assignment of x first before reading x, the same requirement for a local variable. But this checking can be circumvented, because it's impossible to analyze and prevent it fully for field variables
final int x = (this).x+1; // compiles!
In some cases, the compiler goes overboard, preventing legit use cases involving lambda
Runnable r1 = ()->System.out.println(r1); // r1 is a field variable
There's nothing conceptually problematic in this use case; it can be circumvented by (this). too.
What first happens is that the compiler identify the type of the reference then knowing that is a String assign "hello" to str is valid.
I declare my objects outside of an if statement, but initialize them inside of it. Later I try and use them but it won't allow it because they haven't been initialized. The if statements are structured so that they all will execute before the objects are used, and hence the objects will be initialized guaranteed, but java doesn't allow that. Any way around this?
If you know that all paths will ultimately initialize them, but the compiler doesn't, you can initialize them to null or 0 or false (as ajb helpfully reminds) -- or some other special initial value you define -- when declaring them. They then have a concrete initial value.
If the variable is still null (or whatever it's initial value was) by the time you use it (evidenced perhaps by an NPE in the case of an object) then you know something went wrong; you can also self-document your assumptions with asserts later.
You should post your code so we can give you better advice; the compiler is relatively smart about path analysis, although it can't, of course, handle cases that rely on external input or assumed preconditions and invariants. Still, it's always possible that you've overlooked something (perhaps an exception or unexpected condition leads to a path where the value is uninitialized - which is fine, you just have to make sure it's initialized).
The only way an object's initialization is guaranteed after a conditional expression is if there exists a branch that is always executed, such as an else statement, or default in switch statements.
To decompose that, take this example code:
String word;
String name = "Peter";
if("Peter".equals(name)) {
word = "The Bird";
}
System.out.println(word);
This will fail since the compiler identifies a branch in which word is not initialized.
If you add an else clause, then the compiler will believe that word is initialized.
String word;
String name = "Peter";
if("Peter".equals(name)) {
word = "The Bird";
} else {
word = "Nope";
}
System.out.println(word);
Java requires that a variable be initialized along all possible paths to the point of use before its value can be referenced. Eg, if you have
int x;
if (a == b) {
x = 5;
}
if (c == d) {
x = 6;
}
int y = x;
In the above case the compiler cannot know that either the first or second if statement will be true, and so it's not certain that x gets assigned a value along all paths leading to the assignment to y. So the compiler will disallow this (and, if the compiler didn't reject this, the "verifier" inside the JVM would).
The solution is to assign a value to the variable (maybe zero or -1 in this case, null for an object reference) so that it's known to have a value along all paths.
But note that you probably should not just assign a dummy value to every variable you declare, since very often the compiler message that no value is assigned can indicate a real live code bug where you've accidentally omitted assigning a value to the variable along some path.
initialize them to null
Object myAwesomesauceVariableOfAwesome = null;
if(myUnbelievablyWildBoolean){
myAwesomesauceVariableOfAwesome = getAwesomesauce();
}
doSomethingCompletelyMindBlowingWithAwesomesauce(myAwesomesauceVariableOfAwesome);
Here's part of a small program I'm doing as a homework assignment:
public Exam maxGrade() {
Node p = firstNode;
int max = 0;
String name;
while (p!=null) {
if (p.info.getGrade()>max) {
max = p.info.getGrade();
name = p.info.getName();
}
p = p.next;
}
if (name==null)
return null;
else
return searchByName(name);
}
So when I go ahead and compile, the compiler outputs this message:
Student.java:127: error: variable name might not have been initialized
if (name==null)
The problem is easily solved by substituting the fourth line with:
String name = null;
Now, I can see some logic in this. But I'd really like to grasp the workings behind the problem.
I mean, it seems reasonable that the compiler checks whether a variable is initialized if it sees you're doing something with it in your code, but I don't think I'm doing anything that NEEDS the variable to be initialized.
According to sources like this when I simply declare my String (or any other Object) variable "name", it already points to null. Then why is it considered an anomaly to simply check if that value is null? Will the compiler consider an error anything that I do to my uninitialized variable other than assignments?
Fields of object type are initialized to null by default. Array members are also initialized to null by default.
Local variables are not - they must be initialized explicitly.
This is a good thing. Uninitialized variables are frequently an indication of error.
From "Initial Values of Variables" in chapter 4 of the Java Language Specification:
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).
The compiler requires that you initialize the Object to be null if you're making any assumption as to its value. This is simply a (very useful) precaution.
Addendum:The compiler cant check the semantics of your program. Even if you know that a variable is initilized before its first usage the compiler cant.
consider the following function:
public boolean mod2(int i){
if(i % 2 == 0){
return true;
}
if(i % 2 != 0){
return false;
}
}
We all know that this method would always return true or false. The compiler instead cant ensure that there will always be a return value because he has to know that there will only those two results. So the compiler will report an error about a missing return statement.
I need to use something similar to php's isset function. I know php and java are EXTREMELY different but php is my only basis of previous knowledge on something similar to programming. Is there some kind of method that would return a boolean value for whether or not an instance variable had been initialized or not. For example...
if(box.isset()) {
box.removeFromCanvas();
}
So far I've had this problem where I am getting a run-time error when my program is trying to hide or remove an object that hasn't been constructed yet.
Assuming you're interested in whether the variable has been explicitly assigned a value or not, the answer is "not really". There's absolutely no difference between a field (instance variable or class variable) which hasn't been explicitly assigned at all yet, and one which has been assigned its default value - 0, false, null etc.
Now if you know that once assigned, the value will never reassigned a value of null, you can use:
if (box != null) {
box.removeFromCanvas();
}
(and that also avoids a possible NullPointerException) but you need to be aware that "a field with a value of null" isn't the same as "a field which hasn't been explicitly assigned a value". Null is a perfectly valid variable value (for non-primitive variables, of course). Indeed, you may even want to change the above code to:
if (box != null) {
box.removeFromCanvas();
// Forget about the box - we don't want to try to remove it again
box = null;
}
The difference is also visible for local variables, which can't be read before they've been "definitely assigned" - but one of the values which they can be definitely assigned is null (for reference type variables):
// Won't compile
String x;
System.out.println(x);
// Will compile, prints null
String y = null;
System.out.println(y);
Instance variables or fields, along with static variables, are assigned default values based on the variable type:
int: 0
char: \u0000 or 0
double: 0.0
boolean: false
reference: null
Just want to clarify that local variables (ie. declared in block, eg. method, for loop, while loop, try-catch, etc.) are not initialized to default values and must be explicitly initialized.