解析和翻译 Java 8 lambda 表达式

Posted

技术标签:

【中文标题】解析和翻译 Java 8 lambda 表达式【英文标题】:Parsing and Translating Java 8 lambda expressions 【发布时间】:2014-11-17 07:49:58 【问题描述】:

在 C# 中,您可以将 lambda 表达式包含在表达式树对象中,然后可能是 parse it。我想知道这在 Java 中是否也可以实现?

我正在寻找的是做这样的事情:

BooksRepository.getAll()
.where(b -> b.getIban() == "SomeIban")
.and(b -> b.getAuthor() == "SomeAuthor"); //etc.

然后BooksRepository 应该以某种方式将该查询转换为基于指定为 lambdas 的谓词的以下 RESTful API 请求:

GET http://mylibrary.com/books?Iban=SomeIban&Author=SomeAuthor

然后将结果返回给客户端。知道这在 Java 中是否可行?

【问题讨论】:

这是一个崇高的目标,但 lambdas 根本无法帮助您。 Java 中没有可比的。 .where(b -> b.getIban() == "SomeIban")而不是WHERE IBAN = 'SomeIban'(作为SQL语句的一部分)有什么好处?如果它可以翻译任意 Java 代码,它会很强大,但相应的 C# 功能仅限于简单的表达式,因此它会在可能开始变得有用的地方停止…… @Holger 优点是避免了不透明、非语法检查的字符串。但我更喜欢 jOOQ,因为通过这种方法,您可以在 Java 对象中表示 SQL 的 可重用 部分。另一方面,这种方法是特定于 SQL 的,而不是 OP 在这里询问的内容。 @Holger 重构、编译时间检查、自动完成和底层查询实现的抽象。 @Holger 同意,尤其是您在第一句话中的观点。 lambda 可以是任何东西,只有运行时会报错。更糟糕的是,运行时似乎将“无缝”恢复到 JVM 内处理。 Y-U-C-K。 【参考方案1】:

是的,这是可能的。我制作了一个完全可以做到这一点的库:JaQue

【讨论】:

这很了不起,看到这个项目很少受到关注并且似乎被放弃了,我真的很难过。 LINQ 是一回事,但我认为表达式是 C# 和 .NET 最强大的功能之一,并且执行类型安全、流畅的配置的能力非常强大且富有表现力。 @AviCherry:感谢您的评论。如果您认为该项目很重要,您可以在此处和右侧的一些相关问题中投票。希望它会让它更加明显。顺便说一句,它没有死。我根本没有任何未清项目;-)。毕竟,它是一个具有良好定义的 API 的库。 API 已实现、编写测试、报告并修复了几个错误。【参考方案2】:

我是Jinq 的作者。将 lambda 自动转换为可在运行时读取的表达式树是 C# 独有的功能。对于普通程序员,该功能实际上并没有任何通用用途。它基本上只对实现 LINQ 有用,因此语言设计者并不热衷于将该功能添加到 Java 或其他语言中。一直在谈论为 Java 添加某种编译器插件框架,允许您自己将表达式树功能添加到 Java,但我不太熟悉该项目的进展。

Jinq 包含一个字节码分析框架,可以在运行时从 lambda 的字节码构建简单的表达式树。它基于符号执行和 ASM。它可以用来将 lambdas 转换为表达式树,就像 C# 一样,但它是一个相当重的过程,需要跳过很多圈,所以对于你想要做的事情来说它可能是矫枉过正的。本质上,你会用锤子打苍蝇。

在 JVM 上运行的除 Java 之外的其他语言可以更好地支持您想要执行的元编程。因此,您可能还需要考虑使用 Groovy 或 Scala。

【讨论】:

您好,明博士。你说的完全正确,如果这是我唯一的要求,那么我会“用锤子打苍蝇”,但事实并非如此。实际上,我在问题中给出的示例只是我想到的许多其他事情的简单用例,因为我们正在从双向对象映射(ala automapper)、验证规则(ala fluent validation.net)转向 java 8 , 除了抽象的 RESTful 查询之外,还适用于工作流 DSL。 哦,顺便说一句,我已经阅读了你关于符号执行的文章,并且一直(试图)了解 jinq 的分析包(顺便说一下,非常令人印象深刻的工作),但这非常具有挑战性对我来说是整个 Java 世界的新手。你碰巧有 Jinq 的分析包的任何文档吗? 如果你只是做简单的查询,那么设计一个不需要 lambda 作为输入的更简单的 API 会容易得多。如果您有关于 Jinq 的具体问题,直接给我发电子邮件可能更容易。分析包没有文档。你可以通过查看 jinq-jpa/main/org/jinq/jpa/transform/LambdaInfo.java 文件来了解它是如何使用的。 C# 确实有一些很棒的特性。微软的设计理念是快速为 C# 添加新功能,而不必过多担心破坏旧事物。 Java 发展缓慢,并在这样做之前等待普遍共识。经验表明,Linq 表达式对于构建查询系统很有用,就像您的系统一样。但它们对其他事情有用吗?为什么它们仅限于表达?为什么不使用更强大的元编程功能也适用于语句?这种缺乏共识是 Java 还没有这个特性的原因。 Java 提供注解作为一种笨拙的替代方案。 伙计,你应该冷静一点。我不明白你为什么对编程语言设计这样深奥的事情如此着迷。我有时自己用 C# 编写代码。当我说 C#“快速移动并打破事物”时,我的意思是作为一种恭维,但由于 cmets 的字符限制,我无法详细说明。这是硅谷的方式。人们经常称赞 Apple 弃用了旧的 API。快速移动的自然结果是有些东西会坏掉。 Java 发展缓慢,但有时这太慢了。 C# 使用一组与 Java 不同的权衡取舍。没有语言是完美的。冷静下来,伙计。【参考方案3】:

类似Jinq?

database.customerStream().where(customer -> customer.getName().equals("Alice"));

【讨论】:

没错!请参阅主要问题下的 cmets。【参考方案4】:

我在这里解释我的方法http://benjiweber.co.uk/blog/2013/12/28/typesafe-database-interaction-with-java-8/

基本上,针对记录运行时交互的假对象重放 lambda。

【讨论】:

以上是关于解析和翻译 Java 8 lambda 表达式的主要内容,如果未能解决你的问题,请参考以下文章

Java 8 vs. Scala: Lambda表达式

Effective Java 第三版——42.lambda表达式优于匿名类

Effective Java 第三版——43.方法引用优于lambda表达式

Java中Lambda表达式和Groovy闭包的相关解析

聊聊Java 8的Lambda表达式和函数式接口

JAVA 8 Lambda表达式-Lambda Expressions