2024 年 Clojure 状态调查中分享您的想法!

欢迎!请参阅关于页面以获取关于此信息的更多信息。

+1
编译器

在实现 Cursive 对新函数式接口转换的支持时,我发现了关于 Java 和 Clojure 对这些功能的看法不一致的问题。我想检查这些不一致是否是故意的。

  1. Clojure 要求包含 SAM(单抽象方法)类的类需要有 FunctionalInterface 注解才能有资格进行转换。然而,Java 没有这样的限制,JLS 也没有这个说明:https://docs.oracle.com/javase/specs/jls/se21/html/jls-9.html#jls-9.8。这可能是个问题,因为有可能存在没有注解却可以用在 Java 中 lambda 函数上的库类,但在 Clojure 中却不适用。这在旧版 lambda 库的类中很容易发生。看起来 FunctionalInterface 更多的目的是为了确保一个意图用作 SAM 的接口保持这样,并且不会意外添加方法(《https://docs.oracle.com/javase/specs/jls/se21/html/jls-9.6.4.9》中明确说明了这一点)。实际上,该部分明确指出该注解不是接口为函数所必需的。
  2. 同样,规范指出函数式接口必须是一个接口,但 Compiler.FISupport.maybeFIMethod() 并没有检查这个,它只是检查方法本身是否是抽象的。所以 Clojure 会接受包含 SAM 的抽象类,但 Java 则不会。这似乎在实践中不太可能发生,但也很容易加强,而且我看不出有什么必要不执行这项检查。

2 回答

0
谢谢,我之前没看到。很遗憾1.12版本无法解决这个问题,这似乎可能对人们造成困扰。

无论如何,我想我会实现编译器当前的做法。
0

编辑

1) 我们的目标是找出Clojure函数与Java结构存在语义匹配的地方,并使它们在那里的使用是隐式的。标记为这样的函数接口必须只有一个方法,并且明确表示该意图。SAM接口虽然在结构上相似,但并没有那个明确的意图,可能并不与Clojure函数的语义匹配(而是“过程”或某种非函数概念)。

尽管如此,SAM和方法值的组合是一个有趣的交汇点,我们仍在努力完善。如果你将方法值传递给接受SAM的方法,这是一个我们可以直接适配(如Java使用方法引用)的点,而无需创建方法值包装器并对其进行适配。这是一个没有Clojure函数和不需要语义匹配的地方,我们可能支持,仍待定。

2) maybeFIMethod检查类是否有@FunctionalInterface注解,它只能存在于接口上,因此检查它是否是接口是多余的。

...