在 Java 8 中使用 lambda 出现意外错误

2024-03-02

我正在使用 Java 8 Update 20 32 位、Maven 3.2.3、Eclipse Luna Build id:20140612-0600 32 位。

开始使用 lambda 后,我的项目中的一些类开始在 Maven 中报告编译错误(mvn compile).

仅当我使用 lambda 时才会出现这些错误。如果我切换回匿名类,错误就会消失。

我可以通过一个简单的测试用例重现该错误:

package br;

import java.awt.Button;
import java.awt.Panel;

public class Test {

    private final Button button;
    private final Panel panel;

    public Test() {
        button = new Button();
        button.addActionListener(event -> {
            System.out.println(panel);
        });
        panel = new Panel();
    }
}

我这样编译:

mvn clean;mvn compile

我收到此错误:

[ERROR] /C:/Users/fabiano/workspace-luna/Test/src/main/java/br/Test.java:[14,44] variable panel might not have been initialized

尽管错误消息非常清楚地说明了正在发生的事情(编译器认为最终变量panel在实例化之前被调用),直到按钮生成一个操作时才会调用该变量,并且我们不能说该操作何时发生,代码应该编译。事实上,如果我不使用 lambda,它会按应有的方式编译:

package br;

import java.awt.Button;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Test {

    private final Button button;
    private final Panel panel;

    public Test() {
        button = new Button();
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println(panel);
            }
        });
        panel = new Panel();
    }
}

我注意到与这个问题相关的另外两个奇怪的事情:

  1. Eclipse 在自动编译该类时不会报告此错误。 Eclipse 使用与 maven 相同的 JDK 来编译该类。
  2. 如果我使用maven使用匿名类来编译该类,然后我将该类更改为使用lambda并再次使用maven进行编译,它不会报告错误。在这种情况下,如果我使用它只会再次报告错误mvn clean其次是mvn compile.

有人可以帮我解决这个问题吗?或者尝试重现这个问题?


尽管错误消息非常清楚地说明了发生的情况(编译器认为最终变量“panel”在实例化之前被调用),但直到按钮生成操作时才会调用该变量,我们不能说当操作发生时,代码应该编译。

您应该考虑这样一个事实:编译器遵循正式规则并且不了解您的知识。特别是,编译器无法知道该方法addActionListener不调用actionPerformed立即方法。它也不知道按钮的可见性决定了何时actionPerformed可能会被称为。

正式行为有规格 http://docs.oracle.com/javase/specs/jls/se8/html/index.html。在那里你会发现以下几点:

第 16 章 明确分配 http://docs.oracle.com/javase/specs/jls/se8/html/jls-16.html

每个局部变量(第 14.4 节)和每个空白final字段(§4.12.4,§8.3.1.2)必须有一个明确指定当对其值进行任何访问时的值。

对其值的访问由变量的简单名称组成(或者,对于字段,由以下条件限定的字段的简单名称)this) 出现在表达式中的任何位置,但作为简单赋值运算符的左侧操作数除外=(第 15.26.1 节)。

and

15.27.2。拉姆达身体 http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27

与匿名类声明中出现的代码不同,名称的含义和this and super出现在 lambda 主体中的关键字以及引用声明的可访问性与周围上下文中的相同(除了 lambda 参数引入了新名称)。

在您的代码中,lambda 体内名称的含义是panel,与周围上下文中的构造函数相同。在这种情况下,“每个空白final字段必须有一个明确指定当发生对其值的任何访问时的值”适用。

是的,这与内部类定义不同。该规范明确指出。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Java 8 中使用 lambda 出现意外错误 的相关文章

随机推荐

  • Python/ Pandas:找到左右最大值

    我有一个 pandas 数据框 第一列中有一个区域 其余部分有 8 年的季度数据 大约有 4400 行 这是一个示例 idx Q12000 Q22000 Q32000 Q42000 Q12001 Q22001 Q32001 Q42001 Q
  • Android LocationServices.checkLocationSettings 误报结果

    目前受影响的设备 Xperia 1 II 小米红米Note 7 Use 为了请求位置更新 我检查位置设置 事先就足够了 如果没有 我会显示一条小文字 表明服务必须 为我的功能启用 如果用户单击它 系统对话框将启用 会提示定位服务 我如何运行
  • 在一列中添加多个值

    我必须按如下所示的方式创建一个表 我们可以这样创作吗 如果是 表名 示例 product id product name category 1 Sample1 1 2 3 2 sample2 4 5 6 其中类别字段包含多个值 我们如何搜索
  • 使用 vector 作为缓冲区,而不在 resize() 上对其进行初始化

    我想用vector
  • Powershell:确定进程是 32 位还是 64 位

    有没有办法确定给定的进程 ID 是 32 位进程还是 64 位进程 我正在使用 Powershell v3 0 尝试这个 Add Type MemberDefinition DllImport kernel32 dll SetLastErr
  • 改造响应保留旧数据并将新数据添加到 editText 搜索的数据中

    我正在使用 editText 搜索从 API 获取数据 第一次搜索时 它按预期工作 但在第二次搜索时 它不会显示唯一的新响应 而是保留旧响应并在其末尾添加新响应 它的行为就像缓存以前的一样 我该如何修复该问题以仅显示最后一个搜索词结果 分段
  • Google 云端硬盘文件列表:500 错误

    对于我们的应用程序 我们使用具有 2 足授权的 Google Drive SDK 我们使用 Drive SDK 很长时间了 但今天我们遇到了 Files list API 的新问题 https developers google com d
  • 用于一对多查找的 Cassandra 数据建模

    考虑存储用户及其联系人的问题 大约有一亿用户 每个用户有几百个联系人 平均联系人大小为 1kb 可能有些用户拥有太多联系人 gt 5000 并且可能有一些联系人比平均 1kb 大得多 例如 10 倍 用户会主动添加联系人 但很少会删除联系人
  • 使用 Ansible 配置 Jenkins 2.0

    我使用 Ansible 来配置我们的服务器 我安装了 Jenkins 2 0 但当我打开 Web UI 时 它变成了启动配置 我如何使用 Ansible 或 shell 或 jenkins cli 来做到这一点 CentOS 7 Ansib
  • 登录时从用户集合中获取用户数据

    我目前正在开发一个在客户端初始化了 firebase 的应用程序 当用户通过 firebase 登录时 我想从 firestore 获取用户的数据 我目前正在这样做onAuthStateChanged侦听器并成功获取用户 我想知道这是否是获
  • 套接字连接超时:规范在哪里?

    我的工作环境是我的局域网 下面的代码示例是用 Java 语言编写的 但我的问题是关于 TCP 而不是编程 我遇到过以下连接超时的情况 2 ms when connection established 当主机处于活动状态但未侦听指定套接字端口
  • emacs lisp 中的 let 和 flet

    我不知道你是否会称其为规范公式 但为了绑定本地函数 GNU 手册建议我使用 flet defun adder with flet x flet f x x 3 f x 然而 我偶然尝试了 在玩了一会儿Scheme之后 下面的表达式 其中我使
  • 将给定字符串转换为具有给定子字符串的回文

    给定字符串 S1 和字符串 S2 将字符串 S1 转换为回文字符串 例如 S2 是该回文字符串的子字符串 S1 上允许的唯一操作是将任何字符替换为任何其他字符 找出所需的最少操作次数 我已经编写了这段代码 可以计算需要使用常规字符串进行多少
  • AngularJS CORS 问题

    我已经搜索了 200 多个网站 也许有点夸张 但也不是很多 来了解如何使用 angularjs 处理 cors 我们有一台运行 Web API 服务器的本地计算机 我们正在开发一个调用 API 获取数据的客户端 当从服务器运行客户端时 我们
  • 计算多维数组中的元素数量

    我有这个代码 loadData function jsonArray var id this attr id for var i in jsonArray id tbody append tr class entry details pag
  • 声音匹配/搜索

    实际上声音匹配 搜索的当前技术水平如何 我目前正在远程参与规划一个 Web 应用程序 该应用程序将包含并公开录制的短音频剪辑 最多 3 5 秒 人名 的数据库 有人提出了是否有可能实现基于用户语音输入的搜索的问题 我的直觉告诉我 从计算和算
  • 如何在同一服务器环境下运行PHP和Tomcat?

    不久前在 AskUbuntu 上问过这个问题 https askubuntu com questions 630897 apache httpd backed by both tomcat and php https askubuntu c
  • TypeScript:类型“EventTarget & Element”上不存在属性“checked”。为什么它不存在?

    我收到此错误 错误 17 35 TS2339 类型 EventTarget Element 上不存在属性 checked 但这绝对是不可能的错误 因为 React 文档说checked确实存在于target的复选框 https reactj
  • 对复合对象数组以及日期范围进行 Elasticsearch 查询

    您好 我有一个问题 如何为具有日期范围和附加字段参数的嵌套复合对象创建弹性搜索查询 如下所示 name A availability partial true dates gte 2020 12 01 lte 2020 12 02
  • 在 Java 8 中使用 lambda 出现意外错误

    我正在使用 Java 8 Update 20 32 位 Maven 3 2 3 Eclipse Luna Build id 20140612 0600 32 位 开始使用 lambda 后 我的项目中的一些类开始在 Maven 中报告编译错