Nested For loop incrementing after termination - java

I've got 2 for loops, one nested inside of another. They loop through a 2D array of buttons to get the source of each button thats been clicked using the action listener.
When the button is found I pass the position/array indexs of the button to an external method. However when the button is found from the array of buttons the first for loop evaluates its termination condition to FALSE but still increments the value of i. Leading to an off by one error. My code is in the standard action performed method, with "event" being the ActionEvent. buttons[][] is a JButton array defined as an instance variable. It is of size 10 x 10 and is already added to the panel.
int i = 0; //this will loop through the columns in the array
int j = 0; //loop through the rows
boolean locatedSource = false; //allows me to escape both loops
for(i = 0; !(locatedSource) && i < buttons.length; i++) //problem here, when i < buttons.length is FALSE i still gets incremented, leading to an off by one error
{
for(j = 0; !(locatedSource) && j < buttons.length; j++)
{
if(event.getSource() == buttons[i][j])
{
locatedSource = true;
break;
}
}
}
//do stuff with i and j in another method. Leads to array out of bounds error / off by one error
}
I should of mentioned, I'm not looking to solve this problem with the use of labels, they seem to be discouraged.

Explanation of the problem
The increment expression of a for loop is executed after each loop iteration not before. See the following quote from the Oracle Java tutorial:
The for statement provides a compact way to iterate over a range of values. Programmers often refer to it as the "for loop" because of the way in which it repeatedly loops until a particular condition is satisfied. The general form of the for statement can be expressed as follows:
for (initialization; termination;
increment) {
statement(s)
}
When using this version of the for statement, keep in mind that:
The initialization expression initializes the loop; it's executed once, as the loop begins.
When the termination expression evaluates to false, the loop terminates.
The increment expression is invoked after each iteration through the loop; it is perfectly acceptable for this expression to increment or decrement a value.
For loop solution
You can re-write your loop so that the increment is the first statement inside the loop.
for (i = 0; !(locatedSource) && i < buttons.length;) {
i++;
for (j = 0; !(locatedSource) && j < buttons.length;) {
j++;
if (event.getSource() == buttons[i][j]) {
locatedSource = true;
}
}
}
While Loop Version
Given that the loop variables are both initialised outside of the loop and you don't want to use a for-loop increment expression it might be clearer to rewrite the code to use while-loops as follows:
while (!(locatedSource) && i < buttons.length) {
i++;
while (!(locatedSource) && j < buttons.length) {
j++;
if (event.getSource() == buttons[i][j]) {
locatedSource = true;
}
}
}

Three possible solutions:
Explicitely set a "found" index and do not reuse your for loop indices.
Factor the searching out in an own method and return directly from the loop.
Decrement i by 1 after finishing the loops.

Use some boolean flag set it in inner loop and check it in the beginning of outer loop.
Here is code:
boolean found = false;
for (i = 0; i < 10; i++) // problem here, when i < buttons.length is FALSE i still gets
// incremented, leading to an off by one error
{
if (found) {
i--;
break;
}
for (j = 0; j < 5; j++) {
if (i == 5 && j == 3) {
found = true;
break;
}
}
//if (found) {
// break;
//}
}

Your code contains a comment "problem here, when i < buttons.length is FALSE i still gets incremented, leading to an off by one error", which is wrong in the ordering of the events.
First the cycle update block gets executed (like i++) and after that the condition is checked (like `i < buttons.length').
Meaning, that i == buttons.length is the correct state after the cycle ends without triggering the locatedSource condition.

Related

how to jump from one for loop to another for loop using label in java?

when i am trying to access for loop from another loop i get following errors.
how can i do that can somebody explain.
public class Test {
public static void main(String...rDX) {
runing:
for (int i = 1; i < 10; i++)
System.out.print(i);
for(int i = 1; i < 10; i++) {
if (i == 5) {
continue runing;
}
}
}
}
error:
java:28: error: undefined label: runing
continue runing;
^
1 error
The JLS says:
The Identifier is declared to be the label of the immediately
contained Statement. ... Unlike C and C++, the Java programming language has no goto statement; identifier statement labels are used with break or continue statements ... appearing anywhere within the labeled statement.
The scope of a label of a labeled statement is the immediately contained Statement.
In your case the for-loop immediatly follwoing the label runing doesn't mention the label. The second for loop tries to continue to the label. But it is not part of the first for-loop, thus the immendiatly following statement.
This results in a compile-time error.
Thus in order to syntactically correct jump from one for loop to another for loop using label you need an outer loop containing the label. But I would argue that's not the right approach.
You can't do that because you can only abort a chain of nested fors and continue on some outer / parent for. You can't continue with other fors that happen to be simply nearby. But you could use that to do e.g.
public class Test {
public static void main(String...rDX) {
runing: for (;;) { // infinite loop
for (int i = 1; i < 10; i++)
System.out.print(i);
for(int i = 1; i < 10; i++) {
if (i == 5) {
continue runing;
}
}
break; // = break runing; effectively never reached
// because above "continue" will always happen
}
}
}
This has the desired(?) effect since it continues with the newly added outer loop which goes back the the first loop.
(?) = at least what it would do when it would compile - I doubt you actually want that because you'll still print 1..10, then in the next step invisibly count to 5 and do nothing with that number.
As LuCio has already stated, the problem here is that the second loop is not part of the first loop.
If you nest the for loops from your example it will work:
public static void main(String[] args) {
runing:
for (int i = 1; i < 10; i++) {
System.out.print(i);
for (int j = 1; j < 10; i++) {
if (j == 5) {
continue runing;
}
}
}
}
Of course this is just an example of how it could work, i'm not sure if this is the actual logic your application requires.

Making ArrayList Size equal to other Array Lists Available in Java

I have 2 ArrayLists of varying sizes. Example -
Array1.size() = 10
Array2.size() = 5
I want at all times these arrays to have same size. Thus, I have another class to ensure this. But obviously, it isn't working for me. Please help!
Below is that Class code -
for (int i = Array2.size(); i == Array1.size(); i++) {
Array2.add(i, "Test");
}
The above loop for just doesn't add 'Test' to the Array2 so it matches the size of Array1. Any ideas guys? Please help!
Your loop uses the wrong condition.
for (int i = Array2.size(); i == Array1.size(); i++) {
Array2.add(i, "Test");
}
This would mean the loop runs while i == Array1.size(), which is of course nonsense.
try
for (int i = Array2.size(); i < Array1.size(); i++) {
Array2.add(i, "Test");
}
As per the doc for loop is:
for (initialization; termination; increment) {
statement(s) }
When using this version of the for statement, keep in mind that:
The initialization expression initializes the loop; it's executed once, as the loop begins.
When the termination expression evaluates to false, the loop terminates.
The increment expression is invoked after each iteration through the loop; it is perfectly acceptable for this expression to increment
or decrement a value.
In your case the loop is:
for (int i = Array2.size(); i == Array1.size(); i++) {
Array2.add(i, "Test");
}
It starts from 5 (Arrays2.size()) and checks whether i==10 which is not true (read false) and so it terminates without doing anything. It does not get into the loop at all.
Since i is never equal to Array1.size(), this loop never adds anything
for (int i = Array2.size(); i == Array1.size(); i++) {
Array2.add(i, "Test");
}

Unnecessary label on continue/break

I have confuse of execution the next code :
label:
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) continue;
if (i == 99) {
continue label;
}
System.out.println("i = " + i);
}
I was hope that this cycle is infinite. But no. When value is 99 - programm was exit. I try to play with continue and break operators but still haven't expected result.
I just try understand why this cycle is not infinite and what i gonna do to make it?
Output :
i = 1
i = 3
......
i = 93
i = 95
i = 97
Process finished with exit code 0
continue continues the labelled loop, which does not involve resetting i to its initial value; so nothing you're doing prevents i from increasing, until it reaches 100 and the loop terminates. And yes, you're correct that the label is unnecessary.
To make it infinite, just reset i within the loop, no need for a label or continue:
for (int i = 0; i < 100; i++) {
if (i == 99) {
i = 0;
}
System.out.println("i = " + i);
}
or perhaps this, which outputs 99 then 0 again and keeps going:
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
if (i == 99) {
i = -1;
}
}
Or if for some reason you really, really wanted to do this with continue, you'd want a second outer loop: http://ideone.com/ofgpK3
label:
while (true) {
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
if (i == 99) {
continue label;
}
}
}
A label is nothing like a goto instruction with what you seem to confuse it with. When you continue a program flow to a labeled loop instruction, you only continue its execution by executing its next loop. When you continue at i = 99, you only execute the for loop with the next iteration value i = 100 what renders the loop's condition i < 100 to be false such that the loop terminates.
What you are trying to achieve would require an outer loop such that:
label: while (true) {
for (int i = 0; ; i++) {
if (i % 2 == 0) continue;
if (i == 99) {
continue label;
}
System.out.println("i = " + i);
}
}
}
Note that I removed the condition within the for loop which is now redundant because the explicit jump back into the outer while loop what implicitly causes the inner loop to terminate. This jump restarts the inner loop and therefore causes the counter to reset to i = 0. In general, such explicit program flow is however difficult to read and easy to confuse such that one should avoid it whenever possible for the same reason as one would want to avoid a goto statement of which labels are very lightweight versions of.
You are continuing with your for loop (And not printing out the number) every time (i % 2 == 0) or if (i == 99) are true. But when i reaches 99, your condition i < 100 is reached and the loop exits.
For an easier infinite loop, use
while(true) {
//Your code
}
or
for(;;) {
//Your code
}
i initialized only once. continue doesn't reset i to 0, so when you reach continue label, the condition in the for loop will be evaluated to false, and you'll skip it.
See the docs:
When using this version of the for statement, keep in mind that:
The initialization expression initializes the loop; it's executed
once, as the loop begins.
When the termination expression evaluates to
false, the loop terminates.
The increment expression is invoked after
each iteration through the loop; it is perfectly acceptable for this
expression to increment or decrement a value.

Translate for loop to a while and do while loop in Java

I created a couple for loops that print lines as such (each new number starts a new line, it doesn't show here):
1
22
333
4444
etc. until it reaches 9 then goes back down to 1.
I am supposed to translate it into both a while and do while loop and have been trying for the past hour and can't seem to do it.
public static void main(String[] args) {
for (int x=1; x <= 9; x++) {
for (int y = 1; y <=x ; y++){
System.out.print( x + "");
}
System.out.println();
}
// TODO code application logic here
for (int x=9; x >=1; x--) {
for (int y = 1; y <=x ; y++){
System.out.print( x + "");
}
System.out.println();
} int y =1;
int x = 1;
while (x <9){
while (y <=x){
y++;
System.out.print(x +"");{
}
System.out.println();
}
x++;
}
A for loop statement has three parts in the for (init; condition; post). These parts are separated by semicolons. The init part specifies an initial statement, the condition is what determines if the loop body is executed or not and the post specifies a post loop statement.
You can do the same thing with a while loop except that instead of a single statement, it is actually several statements. However a while loop is not exactly like a for loop since the continue statement and how it behaves is a concern. More about that later.
A hint is that the various parts of the for statement are separated by semicolons which are also used to separate statements in Java.
Consider the following for loop source example.
int i;
for (i = 0; i < 5; i++) {
// for loop body
}
So you would have an init statement before the loop statement, i = 0 then the loop statement itself containing the condition, i < 5, and as the last line in the loop before the closing curly brace, you would put the post loop condition, i++.
The do while is a bit more complicated because of when the while condition is evaluated. In both the for loop and the while loop, the condition is evaluated and if the expression is not true then the loop body is not executed at all, it is skipped. In the case of the for loop, the init statement is executed and then the condition is evaluated to determine if the for loop body should be executed. Since a while loop does not have an init statement as part of the while statement, the condition is evaluated and if not true, the while loop body is not executed.
A do while loop has a condition that is not evaluated until after the first time through the do while loop body. So the statements within the do while loop are always executed at least once. Then the do while condition is evaluated and if true, execution returns to the top where the do is and the do while loop body is executed again.
Some code of several variations of loops where the init is i = 0 and where the condition is i < 5 and the post is i++. In all cases I have the variable i defined out side of the loop body. In the case of a for loop, defining the variable i within the for statement causes the scope of the variable i, its visibility, to be restricted to the for loop body which would not be the case for the other types of loops.
int i;
for (i = 0; i < 5; i++) {
// for loop body
}
int i = 0;
while (i < 5) {
// while loop body
i++;
}
int i = 0;
do {
// do while loop body
i++;
} while (i < 5);
I mentioned that what happens when the continue statement is executed can make a difference when comparing these forms of loops. The way to think of it is that when a continue statement is executed then there is a jump to the closing brace of the loop statement enclosing the continue statement. So this introduces something to consider.
Look at the above examples but with a continue statement. In all of the examples below there is a continue statement which causes execution to skip to the end of the loop body when the variable i has a value of 3.
With this change the for loop will continue incrementing the variable i because it's post, the third part of the for statement, is executed at the end of the loop. However with the while loop and the do while loop, the incrementing of the variable i is part of the loop body so when the continue is executed skipping to the end of the loop, the increment of the variable i is also skipped.
int i;
// first time init variable i to zero then evaluate condition
for (i = 0; i < 5; i++) { // evaluate condition and execute loop body if true
// for loop body
if (i == 3)
continue; // when i == 3 continue is executed to skip to end of loop
} // at point of braces, post executed, condition evaluated
int i = 0;
while (i < 5) { // evaluate condition and execute loop body if true
// while loop body
if (i == 3)
continue; // when i == 3 continue is executed to skip to end of loop
i++; // variable i only incremented when this statement is executed
} // braces indicate end of loop so jump back to top of loop
int i = 0;
do {
// do while loop body
if (i == 3)
continue; // when i == 3 continue is executed to skip to end of loop
// more statements which may be skipped by the continue
i++; // variable i only incremented when this statement is executed
} while (i < 5); // evaluate condition and jump to top of loop if true
You could make a change to the do while loop while condition to move the incrementing of the variable i into the while condition evaluation by using a pre-increment operator, the ++ operator, on the variable as in the following. We use the pre-increment operator because we want to increment the variable i before we check its value.
int i = -1; // need to start at -1 since the while will increment at beginning of the loop
while (++i < 5) { // increment variable i, evaluate condition and body of loop if true
// while loop body
if (i == 3)
continue; // when i == 3 continue is executed to skip to end of loop
} // braces indicate end of loop so jump back to top of loop
int i = 0;
do {
// do while loop body
if (i == 3)
continue; // when i == 3 continue is executed to skip to end of loop
// more statements which may be skipped by the continue
} while (++i < 5); // increment variable i, evaluate condition and jump to top of loop if true
Try this as your while loop:
int y = 1;
int x = 1;
while (x < 9) {
y = 1;
while (y <= x) {
y++;
System.out.print(x + "");
}
System.out.println();
x++;
}
A for loop is a construct that is extremely similar to a while loop, except that it provides some extra niceties that reduce boilerplate code.
The beginning of a for loop sets your initial variable (in your case, x), your condition clause (x <= 9) and your incrementor (x++). A while loop does not do these things for, it simply runs a block of code while the condition clause in the () is met.
Converting a for loop to a while is simple-
for(int x = 0; x < 10; x++) {
int x = 0;
while(x < 10) {
x++;
}
The while loop has all the same features as the for loop, but without the syntactic sugar. This should help you convert the loops in your question, and in general.

Compiler error: "not a statement"

This is the code snippet:
boolean nodesFiltered = false;
filterSet = newNodeSet;
int filterSize;
int i;
for (; predIter.hasNext(); i < filterSize)
{
eachPred = (Predicate)predIter.next();
filterSize = filterSet.size();
i = 0; continue;
contextNode = filterSet.get(i);
if (contextNode != null)
{
List list = new ArrayList(1);
list.add(contextNode);
predContext.setNodeSet(list);
predContext.setPosition(i + 1);
predContext.setSize(filterSize);
predResult = eachPred.evaluate(predContext);
Where it says i < filterSize) the compiler says I have an error... It says that it isn't a statement...
Indeed, this line is incorrect:
for (; predIter.hasNext(); i < filterSize)
In Java (and all other C-syntax languages) for statement has the following structure:
for(initialization; termination; increment) {
statements...
}
where:
initialization statement is called once, when the loop starts
termination boolean expression is evaluated before each iteration. If it yields false, loop terminates
increment statement is called after every iteration.
Effectively every for loop can be expressed as while loop:
initialization;
while(termination) {
statements;
increment;
}
As you can see in your code snippet increment block is a boolean expression (returns boolean) while it should be a statement (it should "do" something, like incrementing some variable). This is what the compiler is trying to say.
The last part of the for loop should be a statement -- it's what will be executed when control hits the bottom of the loop.
Remember, for a for loop for(int i = 0; i < foo; i++), control goes like this:
int i = 0; (perform initializer statement)
i < foo; (perform conditional check)
if yes, execute the body of the loop.
i++ (perform increment step)
Back to 2.
As you can see, 4. needs something to happen, rather than just getting the value of an expression.
What you did wrong was that in a for loop the code sequence is:
for(i=0; i<10; i++) {
//Code goes here
}
The problem is:
//You did *no* initialization, the order was wrong, and no increment.
for (; predIter.hasNext(); i < filterSize) //wrong
for (i=0; i < filterSize; i++) //Right
Hope this helps!

Categories