如何将字符串转换为lambda表达式?

时间:2014-03-05 19:34:34

标签: java lambda java-8

我正在考虑一下并想出一个有趣的问题,假设我们有一个配置(输入)文件:

x -> x + 1
x -> x * 2
x -> x * x
x -> -x

此外,我们有一个Integer s列表:

List<Integer> list = new ArrayList<>();
list.addAll(Arrays.toList(1, 2, 3, 4, 5));

有没有办法将String s(x -> x + 1等)转换为代表lambda表达式的Object?然后可以用作:

Object lambda = getLambdaFromString("x -> x + 1");
if (lambda.getClass().equals(IntFunction.class) {
    list.stream().forEach()
        .mapToInt(x -> x)
        .map(x -> ((IntFunction)lambda).applyAsInt(x))
        .forEach(System.out::println);
}

我如何编写这样的方法getLambdaFromString

  • 我可以从JDK / JRE中重用一些内容吗?
  • 我需要自己写这些吗?
  • 是否可以将Object lambda缩小到仅捕获lambda的其他内容?

1 个答案:

答案 0 :(得分:28)

Marko对这个问题的评论是正确的。您无法从文件中读取裸Java lambda表达式,因为如果没有上下文提供的目标类型,则不会定义此类表达式。例如,请考虑以下方法声明:

void method1(BiFunction<String,String,String> f) { ... }
void method2(BiFunction<Integer,Integer,Integer> f) { ... }

然后在下面的代码中,

method1((x, y) -> x + y);
method2((x, y) -> x + y);

两个lambda表达式(x, y) -> x + y表示完全不同的事物。对于method1,+运算符是字符串连接,但对于method2,它表示整数加法。

这在你的问题上有点偏远,但你可以使用动态语言阅读和评估lambda或函数表达式。在Java 8中有Nashorn JavaScript引擎。因此,您可以使用从Java调用的Nashorn来读取和评估 JavaScript 函数,而不是尝试读取Java lambda表达式。

以下代码在arg [0]中使用一个函数并将其应用于每个后续函数,打印结果:

import java.util.function.Function;
import javax.script.*;

public class ScriptFunction {
    public static void main(String[] args) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
        @SuppressWarnings("unchecked")
        Function<Object,Object> f = (Function<Object,Object>)engine.eval(
            String.format("new java.util.function.Function(%s)", args[0]));
        for (int i = 1; i < args.length; i++) {
            System.out.println(f.apply(args[i]));
        }
    }
}

例如,运行命令

java ScriptFunction 'function(x) 3 * x + 1' 17 23 47

给出结果

52.0
70.0
142.0

为了在Nashorn的JavaScript函数概念和Java的Function接口之间创建一个适配器,必须在new java.util.function.Function内包装函数字符串。 (可能有更好的方法,但我不知道一个。)eval返回值Function<Object,Object>的转换导致未经检查的强制警告,我认为这是不可避免的,因为这是JavaScript(一种动态类型语言)和Java(静态类型)之间的界限。最后,没有进行错误检查。如果某些假设被违反,我肯定会以各种令人讨厌的方式爆炸,例如第一个参数实际上并不代表JavaScript函数。

但是,如果您需要评估从文件中读取的表达式或函数,您可能会发现此技术很有用。