Reputation: 183
This program is the final assignment for my class and I'm have issues figuring out why I'm receiving the error "local variables referenced from an inner class must be final or effectively final". The program is running concurrent threads to sort an array of #'s and then find the high and low values of that array. When I created it without the concurrency, I didn't have this error. I'm struggling as to where to finalize the high and low variable.
public void HiLo(int[] numbers){
int high = numbers[0];
int low = numbers[0];
Runnable r2 = new Runnable(){
@Override
public void run() {
System.out.println("The highest value is: ");
for (int index = 1; index < numbers.length; index++){
if (numbers[index] > high)
high = numbers[index];
System.out.println(high);
}
System.out.println();
System.out.println("The lowest value is: ");
for (int ind = 1; ind < numbers.length; ind++){
if (numbers[ind] < low)
low = numbers[ind];
System.out.println(low);
}
}
};
pool.execute(r2);
}
This is the block of code producing the error. If I make either the int high = numbers[0]; or int low = numbers[0]; final then I get an error that I can't make that value final and the error for the opposite variable disappears.
Here is the rest of the program. Any help is appreciated.
package concurrentthread;
import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class ConcurrentThread {
static Executor pool = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
int size;
Scanner keyboard = new Scanner(System.in);
ConcurrentThread sort = new ConcurrentThread();
ConcurrentThread hilo = new ConcurrentThread();
System.out.println("This program will calculate the highest and lowest "
+ "numbers entered by the user \nand also sort them in "
+ "ascending order");
System.out.println();
System.out.print("How many numbers would you like in the array? ");
size = keyboard.nextInt();
final int[] numbers = new int[size];
for (int index = 0; index < numbers.length; index++){
System.out.print("Please enter a number between 1 and 100: ");
numbers[index] = keyboard.nextInt();
}
System.out.println();
sort.Sort(numbers);
hilo.HiLo(numbers);
//System.exit(0);
}
public void Sort(int[] numbers){
int sort = numbers[0];
Runnable r1 = () -> {
Arrays.sort(numbers);
System.out.println("The sorted values are: ");
for (int index = 0; index < numbers.length; index++)
System.out.print(numbers[index] + " ");
System.out.println();
};
pool.execute(r1);
}
public void HiLo(int[] numbers){
final int high = numbers[0];
int low = numbers[0];
Runnable r2 = new Runnable(){
@Override
public void run() {
System.out.println("The highest value is: ");
for (int index = 1; index < numbers.length; index++){
if (numbers[index] > high)
high = numbers[index];
System.out.println(high);
}
System.out.println();
System.out.println("The lowest value is: ");
for (int ind = 1; ind < numbers.length; ind++){
if (numbers[ind] < low)
low = numbers[ind];
System.out.println(low);
}
}
};
pool.execute(r2);
}
}
Upvotes: 13
Views: 50787
Reputation: 11030
Another possibility is to just declare a separate final
variable that can be used. It's pretty rare that "just move your variables into the inner class" will work, that's a special case. For example, this:
for (int i = 0; i < 10; i++) {
fields[i] = new JTextField("");
fields[i].setEditable(false);
fields[i].addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
addComponents(i);
}
});
Can be changed to this:
for (int i = 0; i < 10; i++) {
fields[i] = new JTextField("");
fields[i].setEditable(false);
final int j = i;
fields[i].addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
addComponents(j);
}
});
Be very careful when doing this with reference types. Declaring a final
local variable does little with reference types. If make a final reference class like this:
final var temp = new MyMutableClass();
The fields of that class do not become immutable. You can still modify them, and that's usually very bad. Better to stick to immutable types (make a special immutable type if you can) to avoid errors unless you are certain that you know what you are doing.
Upvotes: 1
Reputation: 159114
You keep updating both high
and low
inside the run()
method, making them by definition not effectively final.
Since you don't need them outside the run()
method anyway, just move the two lines inside.
public void HiLo(int[] numbers){
Runnable r2 = new Runnable(){
@Override
public void run() {
int high = numbers[0];
int low = numbers[0];
System.out.println("The highest value is: ");
Upvotes: 14