I have a JavaFX 8 program (for JavaFXPorts cross platfrom) pretty much framed to do what I want but came up one step short. The program reads a text file, counts the lines to establish a random range, picks a random number from that range and reads that line in for display.
The error is: local variables referenced from a lambda expression must be final or effectively final button.setOnAction(e -> l.setText(readln2));
I am a bit new to java but is seems whether I use Lambda or not to have the next random line display in Label l
, my button.setOnAction(e -> l.setText(readln2));
line is expecting a static value.
Any ideas how I can tweak what I have to simply make the next value of the var readln2 display each time I press the button on the screen?
Thanks in advance and here is my code:
String readln2 = null; in = new BufferedReader(new FileReader("/temp/mantra.txt")); long linecnt = in.lines().count(); int linenum = rand1.nextInt((int) (linecnt - Low)) + Low; try { //open a bufferedReader to file in = new BufferedReader(new FileReader("/temp/mantra.txt")); while (linenum > 0) { //read the next line until the specific line is found readln2 = in.readLine(); linenum--; } in.close(); } catch (IOException e) { System.out.println("There was a problem:" + e); } Button button = new Button("Click the Button"); button.setOnAction(e -> l.setText(readln2)); // error: local variables referenced from a lambda expression must be final or effectively final
You can just copy the value of readln2
into a final
variable:
final String labelText = readln2 ; Button button = new Button("Click the Button"); button.setOnAction(e -> l.setText(labelText));
If you want to grab a new random line each time, you can either cache the lines of interest and select a random one in the event handler:
Button button = new Button("Click the button"); Label l = new Label(); try { List<String> lines = Files.lines(Paths.get("/temp/mantra.txt")) .skip(low) .limit(high - low) .collect(Collectors.toList()); Random rng = new Random(); button.setOnAction(evt -> l.setText(lines.get(rng.nextInt(lines.size())))); } catch (IOException exc) { exc.printStackTrace(); } // ...
Or you could just re-read the file in the event handler. The first technique is (much) faster but could consume a lot of memory; the second doesn't store any of the file contents in memory but reads a file each time the button is pressed, which could make the UI unresponsive.
The error you got basically tells you what was wrong: the only local variables you can access from inside a lambda expression are either final
(declared final
, which means they must be assigned a value exactly once) or "effectively final" (which basically means you could make them final without any other changes to the code).
Your code fails to compile because readln2
is assigned a value multiple times (inside a loop), so it cannot be declared final
. Thus you can't access it in a lambda expression. In the code above, the only variables accessed in the lambda are l
, lines
, and rng
, which are all "effectively final` as they are assigned a value exactly once. (You can declare them final and the code would still compile.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With