Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I was thinking a bit and came up with an interesting problem, suppose we have a configuration (input) file with:

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

And furthermore we have a list of Integers:

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

Is there a way to convert the Strings (x -> x + 1, etc.) to Objects that represent a lambda expression? Which could then be used as:

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);
}

How would I write such a method getLambdaFromString?

  • Is there something I could reuse from the JDK/JRE?
  • Would I need to write it all by myself?
  • Is it possible to narrow down the Object lambda to something else that only captures lambdas?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
119 views
Welcome To Ask or Share your Answers For Others

1 Answer

Marko's comment on the question is correct. You can't read a bare Java lambda expression out of a file, since such an expression isn't defined without a target type provided by the context. For example, consider the following method declarations:

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

Then in the following code,

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

the two lambda expressions (x, y) -> x + y mean completely different things. For method1, the + operator is string concatenation, but for method2, it means integer addition.

This is wandering a bit far afield from your question, but you can read and evaluate a lambda or function expression using a dynamic language. In Java 8 there is the Nashorn JavaScript engine. So instead of attempting to read an evaluate a Java lambda expression, you could read and evaluate a JavaScript function using Nashorn, called from Java.

The following code takes a function in arg[0] and applies it to each subsequent, printing the results:

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]));
        }
    }
}

For example, running the command

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

gives the results

52.0
70.0
142.0

The wrapping of the function string inside of new java.util.function.Function is necessary in order to create an adapter between Nashorn's notion of a JavaScript function and Java's Function interface. (There might be a better way, but I'm not aware of one.) The cast of the return value of eval to Function<Object,Object> results in an unchecked cast warning, which is unavoidable, I think, since this is the boundary between JavaScript, a dynamically-typed language, and Java, which is statically-typed. Finally, no error checking is done. I'm sure this will blow up in a variety of nasty ways if certain assumptions are violated, such as the first argument not actually representing a JavaScript function.

Still, you might find this technique useful if you have a need to evaluate expressions or functions read from a file.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...