首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >事件处理程序有编译错误:“从lambda表达式引用的局部变量必须是final”

事件处理程序有编译错误:“从lambda表达式引用的局部变量必须是final”
EN

Stack Overflow用户
提问于 2020-04-03 02:56:08
回答 1查看 131关注 0票数 1

我已经将所有代码从ActionEvent转移到了一个方法中,但是编译器仍然给我同样的错误:“从lambda表达式引用的局部变量必须是final”。

它来自这里的playerMove()调用:

代码语言:javascript
运行
AI代码解释
复制
for (int row = 0; row < shooterBoard.length; row++) {
    for (int col = 0; col < shooterBoard[row].length; col++) {
        shooterBoard[row][col].setOnAction((ActionEvent e) -> {
            playerMove(memoryBoard, shooterBoard, playerText, winCounter, row, col);
        });
    }
}

我如何解决这个问题,你能解释为什么我会得到它吗?我是编程新手,想要更好地理解它。

下面是我的完整程序:

代码语言:javascript
运行
AI代码解释
复制
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;

import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;

public class BattleshipP2 extends Application{
        Image hit = new Image(getClass().getResourceAsStream("H"));
        Image miss = new Image(getClass().getResourceAsStream("M"));

    public static void grid(String[] args) {
        launch(args);
    }

    public void playerMove(char[][] memoryBoard, Button[][] shooterBoard, TextArea playerText, int winCounter, int row, int col) {


        if (memoryBoard[row][col] != 'X') {
                            if (memoryBoard[row][col] == '*') {
                                memoryBoard[row][col] = 'X';
                                shooterBoard[row][col].setGraphic(new ImageView(hit));
                                playerText.setText("You attacked " + row + " " + col + " and hit! Great job captain!");
                                winCounter++;
                            } else {
                                memoryBoard[row][col] = 'X';
                                shooterBoard[row][col].setGraphic(new ImageView(miss));
                                playerText.setText("You attacked " + row + " " + col + " and missed! Nice try captain!");
                            }
                        } else {
                            playerText.setText("Invalid Move!");
                        }
    }

    public static void loadFile(Button[][] board, char[][] memoryBoard, String fileName, TextArea text, boolean status) {
        try {
            Scanner file = new Scanner(new File(fileName));
            while (file.hasNextLine()) {
                for (int row = 0; row < board.length; row++) {
                    for (int col = 0; col < board[row].length; col++) {
                        if (status) {
                            board[row][col].setText(file.next());
                        } else {
                            memoryBoard[row][col] = file.next().charAt(0);
                            board[row][col].setText("*");
                        }   
                    }
                }
            }
        }
        catch (FileNotFoundException exception) {
            text.setText("Error opening file");
        }
    }

    public void start(Stage primaryStage) {
        GridPane gridPane = new GridPane();

        TextArea playerText = new TextArea("PLAYER.txt");
        TextArea cpuText = new TextArea("CPU.txt");
        Label promptP = new Label("Player Messages");
        Label promptC = new Label("CPU Messages");
        Label xAxis = new Label("");
        Label yAxis = new Label("");
        Label xAxis2 = new Label("");
        Label yAxis2 = new Label("");
        Button[][] shooterBoard = new Button[10][10];
        Button[][] playerBoard = new Button[10][10];
        char[][] memoryBoard = new char[10][10];
        int winCounter = 0;
        Scene scene = new Scene(gridPane, 440, 300);

        gridPane.add(xAxis, 1, 0, 10, 1);
        gridPane.add(yAxis, 0, 1, 1, 10);

        xAxis.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("cols.png"))));
        yAxis.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("rows.png"))));

        for (int row = 0; row < shooterBoard.length; row++) {
            for (int col = 0; col < shooterBoard[row].length; col++) {
                playerBoard[row][col] = new Button();
                playerBoard[row][col].setPrefWidth(50);
                playerBoard[row][col].setPrefHeight(50);
                gridPane.add(playerBoard[row][col], 1 + col, 1 + row, 1, 1);
            }
        }

        gridPane.add(xAxis2, 12, 0, 10, 1);
        gridPane.add(yAxis2, 11, 1, 1, 10);

        xAxis2.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("cols.png"))));
        yAxis2.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("rows.png"))));

        for (int row = 0; row < shooterBoard.length; row++) {
            for (int col = 0; col < shooterBoard[row].length; col++) {  
                shooterBoard[row][col] = new Button();
                shooterBoard[row][col].setPrefWidth(50);
                shooterBoard[row][col].setPrefHeight(50);
                gridPane.add(shooterBoard[row][col], 12 + col, 1 + row, 1, 1);
            }
        }

        promptP.setFont(Font.font("Boulder", FontWeight.BOLD, 14));
        promptC.setFont(Font.font("Boulder", FontWeight.BOLD, 14));
        playerText.setFont(Font.font("Boulder", FontWeight.BOLD, 22));
        cpuText.setFont(Font.font("Boulder", FontWeight.BOLD, 22));
        promptP.setTextFill(Color.web("#0000ff", 0.8));
        promptC.setTextFill(Color.web("#FF0000" , 0.8));
        playerText.setStyle("-fx-text-inner-color: blue;");
        cpuText.setStyle("-fx-text-inner-color: red;");

        gridPane.add(promptP, 0, 11, 3, 1);
        gridPane.add(playerText, 0, 12, 22, 1);
        gridPane.add(promptC, 0, 13, 3, 1);
        gridPane.add(cpuText, 0, 14, 22, 1);

        primaryStage.setTitle("Battleship GUI");  
        primaryStage.setScene(scene);
        primaryStage.show();

        loadFile(playerBoard, memoryBoard, playerText.getText(), playerText, true);
        loadFile(shooterBoard, memoryBoard, cpuText.getText(), cpuText, false);

        while (winCounter < 17) {
            for (int row = 0; row < shooterBoard.length; row++) {
                for (int col = 0; col < shooterBoard[row].length; col++) {
                    shooterBoard[row][col].setOnAction((ActionEvent e) -> {
                        playerMove(memoryBoard, shooterBoard, playerText, winCounter, row, col);
                    });
                }
            }
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-03 06:51:32

lambda表达式中的变量必须是final,否则会产生意外的行为。

lambda表达式是“匿名类实现,只有一个方法”的简写--过度简化它

在新类的作用域中,任何事情都可能发生在一个变量上,外部不会看到它,也不会有任何影响。(按引用传递vs按值传递)

您有两个选项。使用(有效的)最后一个参数

代码语言:javascript
运行
AI代码解释
复制
// declaring them like this, makes them effectivly final because they aren't be assigned again, but instead declared and instanciated every time wich makes them "effectivley final" 
// the underscore is just for the naming and has no meaning otherwise. Its just, a exact copy of each Value
// but will be "effectivly final" 

int row_ = row;
int col_ = col;
String playerText_ = playerText;
... // and so on 
shooterBoard[row][col].setOnAction((ActionEvent e) -> {
                        playerMove(memoryBoard_, shooterBoard_, playerText_, winCounter_, row_, col_);
                    });

使用对象作为包装器,这实际上是最终的。

在javaFX中,你有一个叫做属性的东西,它对于这样的事情非常方便。

不使用原始类型,而是使用“属性包装”,它将只实例化一次,并且将是有效的最终类型,然后每个作用域都能够访问更改。

对于javaFx中的其他事情,这些属性也非常方便。就像更改时的回调。

Playertext示例

代码语言:javascript
运行
AI代码解释
复制
StringProperty playerText = new SimpleStringProperty().

playerText.set("bla bla")
System.out.println(playerText.get());

对于每个参数都应该这样做。

也可以为所有的Patrameters编写自己的对象包装器。

因为您需要: memoryBoard、shooterBoard、playerText、winCounter、row、col

你可以创建一个(有效地)最终的对象,然后传递它。

代码语言:javascript
运行
AI代码解释
复制
public class GameInstanceModel{

   String playerText;
   int winCounter;
   int row;
   int col;
   //... your other Variables.

}

// on lunch 



public void start(Stage primaryStage) {
        GridPane gridPane = new GridPane();
        GameInstanceModel currentGame = new GameInstanceModel();
        // ...

        shooterBoard[row][col].setOnAction((ActionEvent e) -> {
                        playerMove(currentGame);
                    });

}

然后创建

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61004407

复制
相关文章
Visual Studio2019 使用WCF服务
Windows Communication Foundation (WCF) 是一个框架,用于生成面向服务的应用程序。它取代了较旧的进程间通信技术,例如 ASMX Web 服务、.NET 远程处理、企业服务 (DCOM) 和 MSMQ。 WCF 将所有这些技术的功能汇集在一个统一的编程模型下,简化了开发分散式应用程序的体验。 使用 WCF,可以将数据作为异步消息从一个服务终结点发送到另一个服务终结点。 服务终结点可以是由 IIS 承载的持续可用的服务的一部分,也可以是应用程序中承载的服务。 终结点可以是从服务终结点请求数据的服务客户端。 简单消息可以是作为 XML 发送的单个字符或单个单词,复杂消息可以是二进制数据流。
明志德道
2023/10/21
4140
Visual Studio2019 使用WCF服务
Visual Studio App Center 中的 Bug 跟踪服务
我在之前的一篇文章 《使用 Visual Studio App Center 持续监视应用使用情况和问题》 中介绍了 App Center 的基本功能及使用入门,其中 诊断 可以自动手机用户的崩溃或异常,并在 App Center 的网页显示详细的错误信息。
dino.c
2022/05/07
1.7K0
Visual Studio App Center 中的 Bug 跟踪服务
Visual Studio LightSwitch
LightSwitch是一个基于模板的自动化开发Silverlight和HTML5应用程序的工具,不同于一般的基于数据字典,配置生成的应用程序的工具,因为LightSwtich提供的所有模板都是可以扩展的,自定义开发的,包括页面布局,数据源,使用的控件。非常方便植入.net的代码。 LightSwitch是一个被裁剪后的VS产品,用来更容易地进行业务处理(Line of Business,LoB)应用程序的开发,有点类似Access。LightSwitch 提供最简单的方法创建面向云和桌面的商业应用程序。
张善友
2018/01/29
1.6K0
使用Visual Studio 2015 Community 开发windows服务
  昨天研究在.NET下开发Windows服务程序,期间遇到一些小问题,这里仅将自己的开发过程和需要注意的地方写下和广大网友分享……
雪飞鸿
2018/09/05
7390
使用Visual Studio 2015 Community 开发windows服务
【开发环境】安装 Visual Studio Code 开发环境 ( 下载 Visual Studio Code 安装器 | Visual Studio Code )
进入 Visual Studio Code 下载页面 https://code.visualstudio.com/ ;
韩曙亮
2023/03/30
1.9K0
【开发环境】安装 Visual Studio Code 开发环境 ( 下载 Visual Studio Code 安装器 | Visual Studio Code )
Tips in Visual Studio 2008
.NET几乎程序员都在使用visual studio 2008进行开发。可是,你通过它达到最大的开发效率了吗?
williamwong
2018/07/24
1.3K0
Tips in Visual Studio 2008
Visual Studio Code介绍
乐百川
2018/01/09
2K0
Visual Studio Code介绍
visual studio2012产品密钥_visual studio激活码
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/04
3.4K0
visual studio2012产品密钥_visual studio激活码
visual studio code使用教程_visual studio code 权威指南 pdf
既然你点开了这个页面,那就说明要么你不知道 VSCode 上已有拓展「C/C++ Snippets」,要么你对这个拓展不甚满意。对于后者,本文将为你介绍如何在 VSCode 上设置 snippets,并为你提供一套可以直接用的 C 语言 snippets。
全栈程序员站长
2022/09/25
11.2K0
visual studio code使用教程_visual studio code 权威指南 pdf
Visual Studio 2017(V
由于我本人之前一直使用VS进行C、C++编程,所以对这个平台有着很大的好感,这次我要开始学习Python的编程,便决定继续沿用这个平台。
py3study
2020/01/03
9540
基于Visual Studio Code
下载路径:https://code.visualstudio.com/Download,注意系统类型和版本;
py3study
2020/01/10
1.8K0
Visual Studio SnippetDesigner使用
这是一款在Visual Studio上代码片段编辑器插件,可以轻松创建代码片段,为什么要用这个代码片段呢,理由:平常在编码过程中,有许多重复性的代码语句,为了提高编码速度与便捷,就可以把重复性的代码语句存起来,通过快捷方式取出来用。例如在Vs里自带的foreach代码片段:
zls365
2021/03/16
9940
Visual Studio远程调试
网址:https://visualstudio.microsoft.com/zh-hans/downloads/
FlyLolo
2021/11/29
1.4K0
Visual Studio远程调试
汉化你的Visual Studio Code
如果可以,还是直接用英文版的,因为大部分情况下,压根不需要认识几个单词,尤其是如果你长期面对英文环境,慢慢的你就会习惯看英文,从而在阅读英文文档时,不会出现陌生感,利于提升英语阅读能力。
苦叶子
2019/08/12
1.3K0
汉化你的Visual Studio Code
Visual Studio 2005的各个版本
支持正版,做DotNet开发,工具选择不二是Vistual Studio 2005,需要了解各个版本的内容相关的Licence: A:Visual Studio Express Products       (a):Visual Web Developer 2005 Express Edition       (b):Visual Basic 2005 Express Edition       (c):Visual C# 2005 Express Edition       (d):Vi
张善友
2018/01/30
2K0
visual studio 2013 u
计算机上同时安装了python 2.7和python 3.6,visual studio 2013在创建python项目的时候提示“Unsupported python version:3.6”
py3study
2020/01/10
6610
点击加载更多

相似问题

Visual Studio 2017突然停止编译typescript?

10

Visual Studio Typescript

123

Visual Studio 2015 TypeScript

11

Visual Studio TypeScript选项

31

对未部署firestore触发的typescript (Visual Studio)进行测试

10
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文