Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java: Is it possible to set a lambda expression for an array of Buttons is a for loop? If so how?

Tags:

java

javafx

I want to be able to do something like this:

for(i = 0; i < 10; i++) {
    //if any button in the array is pressed, disable it.
    button[i].setOnAction( ae -> { button[i].setDisable(true) } );
}

However, I get a error saying "local variables referenced from a lambda expression must be final or effectively final". How might I still do something like the code above (if it is even possible)? If it can't be done, what should be done instead to get a similar result?

like image 815
Uulamock Avatar asked Mar 18 '23 01:03

Uulamock


2 Answers

As the error message says, local variables referenced from a lambda expression must be final or effectively final ("effectively final" meaning the compiler can make it final for you).

Simple workaround:

for(i = 0; i < 10; i++) {
    final int ii = i;
    button[i].setOnAction( ae -> { button[ii].setDisable(true) } );
}
like image 124
user253751 Avatar answered Apr 07 '23 08:04

user253751


Since you are using lambdas, you can benefit also from other features of Java 8, like streams.

For instance, IntStream:

A sequence of primitive int-valued elements supporting sequential and parallel aggregate operations. This is the int primitive specialization of Stream.

can be used to replace the for loop:

IntStream.range(0,10).forEach(i->{...});

so now you have an index that can be used to your purpose:

IntStream.range(0,10)
         .forEach(i->button[i].setOnAction(ea->button[i].setDisable(true)));

Also you can generate a stream from an array:

 Stream.of(button).forEach(btn->{...});

In this case you won't have an index, so as @shmosel suggests, you can use the source of the event:

Stream.of(button)
          .forEach(btn->btn.setOnAction(ea->((Button)ea.getSource()).setDisable(true)));    

EDIT

As @James_D suggests, there's no need of downcasting here:

Stream.of(button)
      .forEach(btn->btn.setOnAction(ea->btn.setDisable(true)));

In both cases, you can also benefit from parallel operations:

IntStream.range(0,10).parallel()
         .forEach(i->button[i].setOnAction(ea->button[i].setDisable(true)));

Stream.of(button).parallel()
          .forEach(btn->btn.setOnAction(ea->btn.setDisable(true)));
like image 43
José Pereda Avatar answered Apr 07 '23 08:04

José Pereda