简体   繁体   English

从 lambda 表达式引用的局部变量必须是最终的或有效的最终变量

[英]local variables referenced from a lambda expression must be final or effectively final

I have a JavaFX 8 program (for JavaFXPorts cross platfrom) pretty much framed to do what I want but came up one step short.我有一个 JavaFX 8 程序(用于 JavaFXPorts 跨平台)几乎可以做我想做的事,但还差一步。 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));我对 java 有点button.setOnAction(e -> l.setText(readln2)); ,但似乎我是否使用 Lambda 在Label l显示下一个随机行,我的button.setOnAction(e -> l.setText(readln2)); line is expecting a static value. line 需要一个静态值。

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?有什么想法可以调整我必须在每次按下屏幕上的按钮时简单地显示 var readln2 的下一个值吗?

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:您可以将readln2的值复制到final变量中:

    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.第二个不会在内存中存储任何文件内容,而是在每次按下按钮时读取一个文件,这可能会使 UI 无响应。

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).您得到的错误基本上告诉您出了什么问题:您可以从 lambda 表达式内部访问的唯一局部变量是final (声明为final ,这意味着它们必须被赋值一次)或“有效最终”(这基本上意味着您可以在不对代码进行任何其他更改的情况下使它们成为最终版本)。

Your code fails to compile because readln2 is assigned a value multiple times (inside a loop), so it cannot be declared final .您的代码无法编译,因为readln2被多次赋值(在循环内),因此不能将其声明为final Thus you can't access it in a lambda expression.因此您无法在 lambda 表达式中访问它。 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.)在上面的代码中,在 lambda 中访问的唯一变量是llinesrng ,它们都是“有效的最终”,因为它们只被赋值一次。(您可以将它们声明为 final 并且代码仍然可以编译。)

The error you encountered means that every variable that you access inside a lambda expressions body has to be final or effectively final.您遇到的错误意味着您在 lambda 表达式主体中访问的每个变量都必须是最终的或有效的最终变量。 For the difference, see this answer here: Difference between final and effectively final对于差异,请在此处查看此答案: 最终和有效最终之间的差异

The problem in your code is the following variable您的代码中的问题是以下变量

String readln2 = null;

The variable gets declared and assigned later on, the compiler can not detect if it gets assigned once or multiple times, so it is not effectively final.变量在稍后声明和分配,编译器无法检测它是被分配一次还是多次,因此它不是有效的最终变量。

The easiest way to solve this is to use a wrapper object, in this case a StringProperty instead of a String.解决此问题的最简单方法是使用包装对象,在本例中使用 StringProperty 而不是 String。 This wrapper gets assigned only once and thus is effectively final:这个包装器只被分配一次,因此实际上是最终的:

StringProperty readln2 = new SimpleStringProperty();
readln2.set(in.readLine());
button.setOnAction(e -> l.setText(readln2.get()));

I shortened the code to show only the relevant parts..我缩短了代码以仅显示相关部分..

I regularly pass outer object into interface implementation in this way: 1. Create some object holder, 2. Set this object holder with some desired state, 3. Change inner variables in the object holder, 4. Get those variables and use them.我经常以这种方式将外部对象传递给接口实现: 1. 创建一些对象持有者, 2. 将此对象持有者设置为一些所需的状态, 3. 更改对象持有者中的内部变量, 4. 获取这些变量并使用它们。

Here is one example from Vaadin :这是 Vaadin 的一个例子:

Object holder : 
    public class ObjectHolder<T> {
    private T obj;
    public ObjectHolder(T obj) {
        this.obj = obj;
    }
    public T get() {
        return obj;
    }
    public void set(T obj) {
        this.obj = obj;
    }
}

I want to pass button captions externally defined like this :我想传递外部定义的按钮标题,如下所示:

String[] bCaption = new String[]{"Start", "Stop", "Restart", "Status"};
String[] commOpt = bCaption;

Next, I have a for loop, and want to create buttons dynamically, and pass values like this :接下来,我有一个 for 循环,想动态创建按钮,并传递这样的值:

for (Integer i = 0; i < bCaption.length; i++) {
    ObjectHolder<Integer> indeks = new ObjectHolder<>(i);
    b[i] = new Button(bCaption[i], 
        (Button.ClickEvent e) -> {
            remoteCommand.execute(
                cred, 
                adresaServera, 
                 comm + " " + commOpt[indeks.get()].toLowerCase()
             );
         }
        );

        b[i].setWidth(70, Unit.PIXELS);
        commandHL.addComponent(b[i]);
        commandHL.setComponentAlignment(b[i], Alignment.MIDDLE_CENTER);
  }

Hope this helps..希望这可以帮助..

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 尝试更新 CompletableFuture 变量但出现错误:从 lambda 表达式引用的局部变量必须是最终的或有效的最终变量 - Trying to update a CompletableFuture variable but get error : local variables referenced from a lambda expression must be final or effectively final 在迭代HashMap时引用局部变量 - &gt;从lambda表达式引用的局部变量必须是最终的或有效的最终错误 - Referencing a local variable while iterate a HashMap -> local variables referenced from a lambda expression must be final or effectively final error 从内部类引用的局部变量必须是最终的或有效的最终 - local variables referenced from an inner class must be final or effectively final 从lambda表达式引用的局部变量必须是final - Local variables referenced from a lambda expression must be final JSlider和JTextField数组更改侦听器-从内部类引用的局部变量必须是最终的或实际上是最终的 - JSlider and JTextField array change listener - Local variables referenced from inner class must be final or effectively final 可运行的“从内部类引用的局部变量中的计数器必须是最终的或有效地是最终的” - counter in runnable 'local variables referenced from an inner class must be final or effectively final' 从内部类引用的Java MultiThreadding局部变量必须是有效final的final - Java MultiThreadding Local variables referenced from an inner class must be final of effectively final 错误:从内部类引用的局部变量必须是final或有效的final - error: local variables referenced from an inner class must be final or effectively final 从内部类引用的JAVA局部变量必须是final或有效的final - JAVA local variables referenced from an inner class must be final or effectively final “从内部类引用的局部变量必须是最终的或有效的最终变量”-如何解决? - "Local variables referenced from an inner class must be final or effectively final" - How to fix?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM