【问题标题】:Is there a way for Java lambda expression not to have reference to enclosing object?有没有办法让 Java lambda 表达式不引用封闭对象?
【发布时间】:2016-06-08 18:07:58
【问题描述】:

当使用 lambda 表达式时,Java 实际上创建了一个匿名(非静态)类。非静态内部类总是包含对其封闭对象的引用。

当从另一个库调用此 lambda 表达式时,该库可能在​​另一个进程中调用 lambda,调用崩溃并出现类未找到异常,因为它无法在另一个进程中找到封闭对象的类。

考虑这个例子:

public class MyClass {
    public void doSomething() {
        remoteLambdaExecutor.executeLambda(value -> value.equals("test"));
    }
}

Java 会创建一个匿名内部类来实现某些功能接口,并将其作为参数传递给 executeLambda()。然后 remoteLambdaExecutor 将在整个过程中使用该匿名类以远程运行。 远程进程对 MyClass 一无所知,会抛出

java.lang.ClassNotFoundException: MyClass

因为该封闭对象引用需要 MyClass。

我总是可以使用 API 期望的功能接口的静态实现,但这违背了目的并且没有利用 lambda 功能。

有没有办法使用 lambda 表达式来解决它?

更新:我也不能使用静态类,除非它以某种方式导出到其他进程。

【问题讨论】:

  • may invoke lambda in a different process:听起来像一个交叉
  • 也许 Java 是错误的语言。也许您需要一种脚本语言。

标签: java lambda


【解决方案1】:

您最初的前提是错误的。 JRE 将不会生成匿名内部类。它可能会生成一个类,但如果您的 lambda 表达式不访问 this 或该类的非 static 成员,它将不会保留对 this 实例的引用。

但是,这并不意味着该类本身是不必要的。由于该类承载 lambda 表达式的代码,因此总是需要它。在这方面,您使用 static 嵌套类的解决方案并没有改变它的任何内容,因为那时,执行代码所需的是 static 嵌套类。

如果不传输包含要执行的代码的类,就无法将对象传输到远程执行设施(除非该类已经存在于远程站点)。

【讨论】:

  • 换句话说,Java lambda 更像是 C++ 函数指针,而不是 Lisp lambda。 Java lambda 告诉您要运行什么代码,但实际上并不包含该代码。我没有意识到这一点。
  • 否则也无法访问周围范围的变量,请参阅docs.oracle.com/javase/tutorial/java/javaOO/…
  • 嗯,您必须将 转移到另一个站点。由于类文件只是一堆字节,这通常是可能的。对于 lambda 表达式,不要关注生成的类——这些类可以在另一端重新生成(这就是可序列化 lambda 的工作方式)。您只需要传输定义类。但是,如果您首先让两个进程都访问存储的类,会更容易。
  • Lambda 表达式并不意味着改变 Java 语言作为编译语言而不是脚本语言的性质。如果您在远程端有可用的编译器 API,您可以发送源代码并在另一端进行编译,但是,这并不比将类的字节码发送到另一端更简单。 • 所以主要区别不是技术问题,而是分布式网络的维护者被说服部署groovy-all.jar,而不是部署用于分发Java代码(或您的应用程序代码)的库
  • @starwarrior8809 “基本上充当匿名类”是一个模棱两可的术语。为 lambda 表达式生成的类总是与匿名内部类共享一些特征,但即使在它们捕获this 的情况下,仍然存在很多差异。也许this answer 对此有所了解。
猜你喜欢
  • 2016-07-11
  • 1970-01-01
  • 2023-02-15
  • 2014-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-20
  • 2019-02-11
相关资源
最近更新 更多