1

现在使用 java-8,我将一些显式声明转换为 lambda 表达式并得到编译器错误。因此怀疑这是当前 java-8 版本(b105)的“错误”。

示例代码定义了使用和不使用 lambda 表达式的两个 Function 对象。两者都依赖于这些函数使用的谓词。虽然传统实现有效,但 lambda 版本报告错误:

java: 变量 fileExists 可能尚未初始化

这不是完全错误的,但是如果使用函数而不是创建函数本身,则谓词是相关的(因为显式版本运行良好)。我应该报告错误(有人有链接吗?)还是我错过了什么?

public class FileOpener {

public FileOpener(Predicate<File> fileExists) {
    this.fileExists = fileExists;
}

final Predicate<File> fileExists;

final Function<File, FileInputStream> openLambda = file -> {
    try {
        return fileExists.test(file) ? new FileInputStream(file) : null;
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    }
};

// this version compiles
final Function<File, FileInputStream> openFunction = new Function<File, FileInputStream>() {
    @Override
    public FileInputStream apply(File file) {
        try {
            return fileExists.test(file) ? new FileInputStream(file) : null;
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
};

}

4

2 回答 2

1

正如 Edwin Dalorzo 所指出的,错误消息是正确的。初始化顺序在这里很重要。首先字段初始值设定项按在源文件中出现的顺序执行,然后是构造函数。引用变量的 Lambda捕获变量,并且在最终变量(和所有局部变量)的情况下,它们捕获需要初始化变量的变量的实际值。这符合 Java 语言规范并且在 Java 8 中没有改变:

class SimpleTest
{
  SimpleTest()
  {
    first="a string";
  }
  final String first;
  String second=first;
}

在 Java 8 之前的版本中显示完全相同的行为。

于 2013-11-15T12:54:33.360 回答
0

我已经尝试过你的代码并玩了一下......结果,如果你final从 中删除修饰符fileExists,一切都会编译并且工作正常,所以评论中的讨论可能不是 100% 准确,fileExists实际上可以在构造函数中初始化。看起来编译器没有检测到初始化实际上正在发生(嗯?)。

这可能是一个错误...我发现的唯一错误是http://bugreport.sun.com/bugreport/(尽管名称为 SUN,但实际上指向 Oracle 站点)。

PS:我使用的是 10 月 10 日的 b111。

于 2013-10-17T20:31:07.753 回答