Local variable declaration in loop - java

When I ran the following code it gives me compile time error .
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 100; i++)
Test2 obj = new Test2();// Compile time error- Multiple markers at this line
System.out.println(Test2.numCreated());
}
}
class Test2 {
private static long number= 0;
public static long numCreated() {
return number;
}
}
But when i put local variable declaration statement Test2 obj= new Test2() directly within a block every thing works fine.
Can someone explain me reason behind this or why Java developers did this ?

The compiler is very smart, if you ommit the { } then the obj object has no reason to be declared since is out of scope immediatly
remember ommiting the { } means ONLY the next line will belong to the for scope...
you mean for sure instead:
for (int i = 0; i < 100; i++){
Test2 obj = new Test2();
}
But what is scope? here more info
scope is the enclosed area where an object is visible, in this case the object obj is declared inside a for loop, that means you can only work with it inside the loop and it will be ready to be GC as soon as the loop is done...

As Stated by above answer you got the point of missing the braces {} of for loop
Note :If you remove braces, it will only read the first line of instruction. Any additional lines will not be read. If you have more than 1 line of instruction to be executed pls use curly brace - or else exception will be thrown.

If you won't put the braces { }, loop will only execute one statement after it. Since you are declaring obj in that particular line, it won't be of any use afterwards. So the compiler warns you in advance.
You must use { } if you want to execute multiple statements and make use of variables.
for (int i = 0; i < 100; i++){
Test2 obj = new Test2();
System.out.println(Test2.numCreated());
}
Now it will work properly because both statements belong to the loop and are inside the scope of the loop. After the loop is finished executing, the obj will be Garbage collected.

Note that this is not restricted to for loops. The problem is actually that the statement in your example is a "Local Variable Declaration Statement" (jls-14.4), and specifically the following line in the specification:
Every local variable declaration statement is immediately contained by a block.
Your example can be reduced to
if(true)
Test2 obj;
which also does not compile.
As soon as you add a block, it compiles fine:
if(true) {
Test2 obj;
}

Related

Is it possible to declare a variable within a Java while conditional?

In Java it is possible to declare a variable in the initialization part of a for-loop:
for ( int i=0; i < 10; i++) {
// do something (with i)
}
But with the while statement this seems not to be possible.
Quite often I see code like this, when the conditional for the while loop needs to be updated after every iteration:
List<Object> processables = retrieveProcessableItems(..); // initial fetch
while (processables.size() > 0) {
// process items
processables = retrieveProcessableItems(..); // update
}
Here on stackoverflow I found at least a solution to prevent the duplicate code of fetching the processable items:
List<Object> processables;
while ((processables = retrieveProcessableItems(..)).size() > 0) {
// process items
}
But the variable still has to be declared outside the while-loop.
So, as I want to keep my variable scopes clean, is it possible to declare a variable within the while conditional, or is there some other solution for such cases?
You can write a while loop using a for loop:
while (condition) { ... }
is the same as
for (; condition; ) { ... }
since all three bits in the brackets of the basic for statement declaration are optional:
BasicForStatement:
for ( [ForInit] ; [Expression] ; [ForUpdate] ) Statement
Similarly, you can just rewrite your while loop as a for loop:
for (List<Object> processables;
(processables = retrieveProcessableItems(..)).size() > 0;) {
// ... Process items.
}
Note that some static analysis tools (e.g. eclipse 4.5) might demand that an initial value is assigned to processables, e.g. List<Object> processables = null. This is incorrect, according to JLS; my version of javac does not complain if the variable is left initially unassigned.
No it's not possible.
It doesn't really make too much sense either: unlike a for loop where you can set up the initial state of the "looping variable", in a while loop you test the value of an existing variable, akin to the conditional check of the for loop.
Of course, if you're concerned about variables "leaking" into other parts of your code, you could enclose the whole thing in an extra scope block:
{
/*declare variable here*/
while(...){...}
}
Alternatively, convert the while loop into a for loop.
Make a do/while:
String value;
do {
value = getValue();
...your processing
} while (value != null && !value.isEmpty());

In Java, how to solve the error that XXXX cannot be solved as variable?

in the mothod of shoot below, for the two varibles 'hmm' and 'sequences' in the for loop, it always shows error that they cannot be solved as variable, but obviously I have declared them in the 'if' body at the upper part of this method. Why doesn't it recognize 'hmm' and 'sequences'?
public Action shoot(GameState pState, Deadline pDue) {
int totalBirdsOfThisRound=pState.getNumBirds();
boolean HMMinitialized=false;
if (!HMMinitialized){
HMM[] hmm=new HMM[totalBirdsOfThisRound];
initializeHMM(pState,hmm);
HMMinitialized=true;
Vector<Integer>[] sequences=(Vector<Integer>[]) new Object[totalBirdsOfThisRound];
}
for(int i=0;i<totalBirdsOfThisRound;i++){
Bird aBird=pState.getBird(i);
for(int j=sequences[i].getLength();j<aBird.getSeqLength();j++)
sequences[i][j]=aBird.getObservation(j);
hmm[i].estimateModel(sequences[i]);
int lastMove=aBird.getLastObservation();
double[] currentStateDistribution=new double[10];
Arrays.fill(currentStateDistribution, 0);
currentStateDistribution[lastMove]=1;
}
return cDontShoot;
}
Java has block scope. You can only access a variable within the block that it was declared in. Usually a block starts with { and ends with }. But if/while/for with no braces together with the following line can also make up a block. So for hmm to be available inside the for loop you need to declare it in the block that contains the for loop.
Here is a hierarchical view of the blocks in your code:
shoot
hmm // Accessible in for-loop if it's declared here
if-statement
hmm // Not accessible if it's declared here
for-loop i
for-loop j
You are initializing HMM[] hmm in the if condition and if control does not reach inside it would not have been initialized. So put this outside if condition like:
HMM[] hmm = null;
The HMM array is out of scope. Either declare the HMM array outside of the if block or move the for loop into the if block to solve this.

Why does a String need to be initialized even if the assignment will happen later?

I get the "The local variable string may not have been initialized" error with the following code. The code itself doesn't make sense it was written just for the sake of exercise.
public class StringExercise
{
public static void main(String[] args)
{
String string; // initializing here fixes the issue
for (int i = 0; i < 10; ++i)
{
if( (i % 4) == 2 )
{
string = "Number: " + i;
}
}
System.out.println(string); // this is marked as wrong by Eclipse
}
}
To get it working it is sufficient to initialize String as expressed in the comment above.
My question is why is it needed? The method println will never be given null and initialization will happen the first time the condition in the loop returns true. Am I doing something wrong or is it just Java being overcautious over programmer's errors? If the latter, how is it justified from the theoretical point of view?
My question is why is it needed?
Because even though your code is "logically" written so that string will indeed be initialized in the loop, the compiler doesn't know it. All it sees is:
for (loop; elements; here)
if (someCondition)
string = something;
In short: a compiler will not check the logic of your code; it it only smart enough as to check for syntax errors, but after that, the bytecode generation itself is "dumb".
And as Java requires that all variables be initialized before use, you get this compiler error.
The compiler can't guarantee that string = "Number: " + i; will be executed within your for and if.

Is there any difference between these two loops?

Is there any difference performance-wise between the two code snippets below?
for(String project : auth.getProjects()) {
// Do something with 'project'
}
and
String[] projects = auth.getProjects();
for(String project : projects) {
// Do something with 'project'
}
For me, I think the second one is better, but it is longer. The first one is shorter, but I am not really sure if it is faster. I am not sure, but to me it seems like every time that loop is iterated, auth.getProjects is called. Is that not so?
Edit: #StephenC is right, the JLS is a much better place to find an answer for something of this nature. Here is a link to the enhanced for loop in the language specification. In there you will find that there are a few different types of for statements it generates but none of them would call the method more than 1 time.
Simple test shows that the method is only called once
public class TestA {
public String [] theStrings;
public TestA() {
theStrings = new String[] {"one","two", "three"};
for(String string : getTheStrings()) {
System.out.println(string);
}
}
public String[] getTheStrings() {
System.out.println("get the strings");
return theStrings;
}
public static void main(String [] args) {
new TestA();
}
}
Output:
get the strings
one
two
three
So essentially they are the same thing. The only thing that may be beneficial about the 2nd would be if you want to use the array outside the for loop.
Edit
You got me curious about how the java compiler handled this so using the code above I decompiled the class file and heres what the result is
public class TestA
{
public TestA()
{
String as[];
int j = (as = getTheStrings()).length;
for(int i = 0; i < j; i++)
{
String string = as[i];
System.out.println(string);
}
}
public String[] getTheStrings()
{
System.out.println("get the strings");
return theStrings;
}
public static void main(String args[])
{
new TestA();
}
public String theStrings[] = {
"one", "two", "three"
};
}
As you can see the compiler simply restructured your for loop into a standard loop! It also further proves that in fact they are exactly the same after the compiler gets through with it.
Assumng that by in you mean :, there is no difference in performance; they both do the same thing. Even in the first example, auth.getProjects() is executed only once; it can't be executed multiple times, since if it was, the for iteration would have to start over each time, which is not how it works.
I'd recommend using the version you find to be clearer.
There are a few more operations in the second example. Instead of referencing the array directly using the method, you are declaring a new reference variable, storing it in that new variable, then referencing the new variable.
You can check out the bytecode with ASM Bytecode Outline.
BUT, this is micro-optimization. If you need a new reference variable, then create one. If you don't need one, save the work and don't create a new one.
There is no difference.
According to the JLS 14.14.2, an enhanced for loop (for an array type) is equivalent to a regular for loop with the following pattern:
T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
{VariableModifier} TargetType Identifier = #a[#i];
Statement
}
If we substitute for your first example:
for(String project : auth.getProjects()) {
// Do something with 'project'
}
we get:
String[] $a = auth.getProjects();
for (int $i = 0; $i < $a.length; $i++) {
String project = $a[$i];
// Do something with 'project'
}
For your second example:
String[] projects = auth.getProjects();
for(String project : projects) {
// Do something with 'project'
}
we get:
String[] projects = auth.getProjects();
String[] $a = projects;
for (int $i = 0; $i < $a.length; $i++) {
String project = $a[$i];
// Do something with 'project'
}
The two versions of the code are clearly equivalent, and assuming that javac or the JIT is capable of optimizing away the redundant local variable $a, the two versions should perform the same.
Note that the local variable $a is only created once at the start of the loop in both cases.
The second one is better performance-wise, it is not creating a variable multiple times. Therefore, yes, auth.getProjects is being called every time.
Both are same as found above.
But do one thing use 1st approcah and after the for loop, de-reference the projects variable as-
projects = null;
Else, it will stay alive for the complete method life and will consume unnecessary memory.

using { } after semicolon [duplicate]

This question already has answers here:
Anonymous code blocks in Java
(11 answers)
Closed 9 years ago.
In an example of android code given in a book regarding action bar, the sample given is as the following:
MenuItem menu1 = menu.add(0, 0, 0, "Item 1");
{
menu1.setIcon(R.drawable.ic_launcher);
menu1.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
How is using curly braces after a semi-colon possible? There is clearly some concept that I do not understand right here.
They are completely optional in this case and have no side-effect at all. In your example it sole serves to purpose of making the code more readable by intending the property assignment which belong to the control. You could as well do it without the braces. But if you'd use a tool to reformat your code, the indentation is likely gone.
However, if you have a Method and you put {} in there, you can create a new variable scope:
void someMethod() {
{
int x = 1;
}
// no x defined here
{
// no x here, so we may define a new one
string x = "Hello";
}
}
You can start a new scope anywhere in a Method where you can start a statement (a variable declaration, a method call, a loop etc.)
Note: When you have for example an if-statement you also create a new variable scope with that braces.
void someMethod() {
if (someThing) {
int x = 1;
}
// no x defined here
if (somethingElse) {
// no x here, so we may define a new one
string x = "Hello";
}
}
The same is true for while, for, try, catch and so on. If you think about it even the braces of a method body work in that way: they create a new scope, which is a "layer" on top of the class-scope.
It's called anonymous code blocks, they are supposed to restrict the variable scope.
Those are Initialization Blocks.
I don't think this is the correct usage of initialization block.
Apart from the example you have produced, these blocks are just used for initialization purpose. Click Here for detailed view.

Categories

Resources