Passing a variable into an ActionListener - java

Ok, so I couldn't find exactly what I needed anywhere else, so here goes.
How would I go about passing a variable into a function inside an ActionListener()? This is my code.
for(int y = 0; y < 5; y ++) {
for(int x = 0; x < 5; x ++) {
currentRect = (y * 5) + x;
mainButtons.get(currentRect).addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
answerField.setText(questions.get(currentRect).getAnswer());
}
});
}
}
The error is on line six, where it underlines "currentRect", and then complains about this,
Cannot refer to a non-final variable currentRect inside an inner class defined in a different method
What is does is iterate through a group of JButtons (javax.swing) , and then assign the appropriate action listeners based on their position in the ArrayList, however, I can't seem to pass the variable storing their positions into the actionlistener itself, so I'm stuck. I realised while im writing this that I should really use a foreach, so ill change that later. (just a little note to who was gonna point that out) I realize that I cannot also make that variable final, as it is changed during the for loop. I also tried passing the value of the currentRect ((y * 5) + x) into the functions, but to no avail.
Thanks,
andrewgies17

The solution is simple, simply declare a new final variable inside of your block:
for(int y = 0; y < 5; y ++) {
for(int x = 0; x < 5; x ++) {
final int currentRect = (y * 5) + x;
or if you need the value of currentRect outside of the block:
for(int y = 0; y < 5; y ++) {
for(int x = 0; x < 5; x ++) {
currentRect = (y * 5) + x;
final int currentRect2 = currentRect;
and you use currentRect2 instead of currentRect in your anonymous class. This is counterintuitive because it looks like that the final variable is beeing re-initialised each time but in fact, you must see this as a new variable that is initialised only once for each loop of the block.
However, this is not the most intelligent way of solving this problem; because you are creating a brand new anonymous class for each button just for the purpose of storing a small value that is different between them. These can quickly add up on a limited device. A better idea would be to store the value of the currentRect as a tag for each button. This way, you can declare a single instance of the anonymous class in the outer class and reuse it for all buttons.

Related

Why is it allowed to declare a variable in a for loop?

I'm a student currently learning java at school (Beginner) and I was wondering about something.
I have a basic knowledge of coding from other languages and I don't understand a particular thing in Java.
If I were to declare a variable (let's use an int as a example) inside a loop wouldn't that mean that I'm declaring the same variable over and over?
This is what I mean:
for (int i = 0; i < 3; i ++) {
int x = 5;
}
Isn't it the same thing as this? (This one is incorrect)
int x = 5;
int x = 5;
If not, Why? Both of them are / declare the same variable twice, though I know that in loops the variable is local and can't be used outside of the loop (I don't think thats the issue though).
I also know that you can't declare the same variable twice so I don't understand how the first example is legal.
Thanks so much :D
This Question has be solved, Thanks to everyone that helped :D
for (int i = 0; i < 3; i ++) {
int x = 5;
}
is actually equivalent to:
{
int x = 5;
}
{
int x = 5;
}
{
int x = 5;
}
Each x variable is declared in a separate scope.
scope is in one iteration, after end of loop, scope doesn't exist.
simple example:
for (int i = 0; i < 4; i++) {
int x = 0;
System.out.println(x);
x++;
}
output:
0
0
0
0
Lets take 1st expression
for (int i = 0; i < 3; i ++) {
int x = 5;
}
Here scope of variable x is within the loop block
So each time a new loop starts scope is already released.
So there is no error
If you change the same code to like this
for (int i = 0; i < 3; i ++) {
int x = 5;
int x = 5;
}
Now there will be an error as x is already in scope and you are again trying to define.
This is allowed
for (int i = 0; i < 3; i ++) {
int x = 5;
x = 5;
}
as you are resigning the variable
the variable x has life time that begin at when you declare it and ends at the closing block for the for-loop.
in other word x is born when you enter new iteration and dies when iteration ends (or dies at the end of block that contains it)
In each iteration of your loop, a variable x of type int is "created" and assigned the value 5. As soon as the iteration finishes, this variable is "destroyed" and by the next iteration the cycle starts again.
So there are never 2 variables by the same name in the same scope.
It is generally good practice to make the variable avayable to the smallest context possible: if you only need it inside the loop declaring it inside it is considered good practice.
For the loop declaration case, your value gets reassigned basically.
This might proove interesting to read and add further informations on the matter: Declaring variables inside or outside of a loop
This is also a legal thing to do
for (int i= 0; i < 1000000000; i++) {
int j = i & i+1 ;
}
These are legal because at the end of the loop the declared variable "ceases to exists" in order to be reformed the next execution
Well, when you declare int x = 5; inside the loop, you're declaring it in a local scope (which starts from its { to }) so the variable x will be destroyed when it gets out of its scope which means for the next loop iteration, it's a new x so that's why you can do that and since it's destroyed when it gets out of scope it can't be used/seen outside the scope.
Just to clarify the concept of allowing variable declaration in a loop, I've declared the same variable again in the loop, and got error "A local variable or function named 'x' is already defined in this scope"(I wrote this code in C#, but you should get similar message in Java):
If I declare the variable in a different scope outside the loop, there will be no error as the scope is different:
for (int i = 0; i < 3; i++)
{
int x = 5;
}
{
int x = 5;
}
If we couldn't declare variables in loop, we had to write the following code:
{
int x = 5;
// Do something with x=5
}
{
int x = 5;
// Do something with x=5
}
{
int x = 5;
// Do something with x=5
}
But with loop, we can just write the following instead of writing 3 scopes:
for (int i = 0; i < 3; i++)
{
int x = 5;
// Do something three times with x=5
}

Counting the amount of a specific object in 2D Array Java

In a checkers game for my CS class I have run into trouble with counting how many of a specific color piece are on the board.
Here is the getter method:
public int getCheckersBlue()
{
int counter = 0;
for(int x = 0; x <= 8; x++)
{
for(int y = 0; y <= 12; y++)
{
if(c[x][y].equals(Color.BLUE))
{
counter++;
}
}
}
return counter;
}
The constructor for c:
private CheckersBoard[][] c = new CheckersBoard[8][8];
Whenever trying to run the game in Greenfoot a null pointer exception is thrown even when the code compiles. Even with everything declared, everything has something it's pointing to. Any suggestions?
I see two major problems in your code:
You're iterating over 0-8 elements for x and 0-12 for y, but in declaration you has 0-7 for x and the same for y
NullPointerException. This caused because array declaration will fill your array with null values, so you're comparing null with Color.Blue which is incorrect.
With the both fixes code will look like this
public int getCheckersBlue()
{
int counter = 0;
for(int x = 0; x < 8; x++)
{
for(int y = 0; y < 8; y++)
{
if(Color.BLUE.equals(c[x][y]))
{
counter++;
}
}
}
return counter;
}
But I think it's still logically incorrect.
Okay, a few of things...
You are iterating through 12 every time in the inner loop when it should be 8.
Color.Blue is a JavaFX Paint, I believe. This is not really what you should be using. Unless you have made your own Enumeration type of Color, you should do so. Here is a link for how to do so with relevant examples.
You are checking equality of two different types: CheckersBoard and Color. You should have a CheckersBoard.getSpace(x, y).getColor() or CheckersBoard.getSpace(x, y).getOccupancy() (which should have a NoOccupancy option) if we want to be completely logistically sound with our naming.

Can someone please explain to me what the java code here is doing?

I am learning java using the headfirst Java book. I have a problem understanding what some Java do and how an output came to be. For example:
class MultiFor {
public static void main(String[] args) {
// write your code here
int x = 0;
int y = 30;
for (int outer = 0; outer < 3; outer++){
for (int inner = 4; inner > 1; inner--){
x = x + 3;
y = y - 2;
if (x == 6){
break;
}
x = x + 3;
}
y = y - 2;
}
System.out.println(x + " " + y);
}
}
my output is 54 6, but i don't know how it came to be. Can someone explain this?
The For-Loops works that way:
for(initialisation ; condition; steps){
do Stuff
}
initialisation is the part where Variables are defined not necessary Variables for the condition but they are only reachable in the for-loop.
condition as long as the condition is true the will run again.
steps mostly an interation for the loops in this case its outer = outer +1 and inner = inner -1.
in this example the outer for-loop runs from outer=0 to outer=2 and the inner runs from inner = 4 to inner = 2.
In the If-Condition is tested on x == 6 after reaching this true status it will stop the inner for-loop with a break;.
thats what it do how it reachs the expected values is just counting the loops and adding values.

String Arrays not working. Compiler not interacting

I was learning how to sort arrays with different types of value holders. I tried to sort an array with Strings, but it comes up with the error message, Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
at SortingArrays.main(SortingArrays.java:50)
There aren't any errors the compiler found, but it comes up with this. The array with numbers worked fine, but the strings didn't. Here is my code.
import java.util.Arrays;
public class SortingArrays {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] aryNums;
aryNums = new int[6];
aryNums[0] = 7;
aryNums[1] = 89;
aryNums[2] = 45;
aryNums[3] = 234;
aryNums[4] = 2;
aryNums[5] = 75;
Arrays.sort(aryNums);
int i;
for (i = 0; i < aryNums.length; i++) {
System.out.println(aryNums[i]);
}
String[] aryStrings;
aryStrings = new String[5];
aryStrings[0] = "I have no idea what I'm doing.";
aryStrings[1] = "Should I know what I'm doing?";
aryStrings[2] = "I guess not.";
aryStrings[3] = "There's my boss.";
aryStrings[4] = "Whoop, he's looking. Hide!";
Arrays.sort(aryStrings);
int x;
for (x = 0; x < aryStrings.length; x++) {
System.out.println(aryStrings[i]);
}
}
}
You are getting runtime exception. ArrayIndexOutOfBoundsException means you are trying to access array beyond its capacity with what its defined.
Problem is with this code:
for (x = 0; x < aryStrings.length; x++){
System.out.println(aryStrings[i]);
^^
}
You are using i as index instead of x. Here i (after your print statements) would be 6 in your case and your array can hold 5 elements which start with 0 and ends with 5.
At the very end of your program:
System.out.println(aryStrings[i]);
i = 6, of course it out of bounds
What you need is:
System.out.println(aryStrings[x]);
i after your first loop is 6.
so here
for (x = 0; x < aryStrings.length; x++){
System.out.println(aryStrings[i]); // i here is 6 but there are 5 elements in aryStrings
}
use x in this loop not i
As other commenters have said, the problem is with your iterating variable.
But to completely avoid this problem, use a for-each loop.
As Joshua Bloch says in Effective Java, 2nd Edition (Item 46):
// The preferred idiom for iterating over collections and arrays
for (int aryNum : aryNums) {
System.out.println(aryNum);
}
Or better in Java 8:
Arrays.stream(aryNums).forEach(System.out::println);
You're using i instead of x in the second print statement
Change the index in x
System.out.println(aryStrings[x]);
As the other answers have stated, by the time you reach your second loop, i is equal to a higher integer than your String array has indices.
Another way to fix your issue is to reset the value of i:
int x;
i = 0;//re-initialize
for (x = 0; x < aryStrings.length; x++) {
System.out.println(aryStrings[i]);
}
However, this defeats the purpose of your x variable.
As a rule of thumb, I'd keep your incrementer local to your loop to prevent problems like this arising:
//declare x in the loop
for (int x = 0; x < aryStrings.length; x++) {
System.out.println(aryStrings[x]);
}

Android: Database Fields not populating through a loop

I am currently trying to make a function to prepopulate fields and determine if they have been set up or not. I need to add a total of 46 entries into my database so I figured a for loop would come in handy:
public void prepopulate() {
Locker setup = new Locker(this);
for (int x = 46; x < 47; x++) {
setup.open();
String lockerNumber = "Locker" + x;
setup.createLockerEntry(lockerNumber, 0);
setup.close();
}
I
Any ideas, maybe a for loop wont work?
if you want to add 46 entries the why are you using for (int x = 46; x < 47; x++). This will work only for one entry.
Just change you for loop like
for (int x = 0; x < 46; x++) //or any appropriate condition

Categories