Java可变代码

时间:2015-11-11 01:17:22

标签: java function

我将在我的代码中声明并运行一个Task,但是这个Task需要一个基于用户输入的函数。 (如果用户说>我必须使用它),但由于可能性太大,我不能只是超载。

所以我需要这样的东西; 如果用户说:

x+3/y+5

我将转向此

Function(int x,int y)
{
    return x+(3/y)+5;
}

我将在String中使用它。但通常我的应用等待是:

Task a = new Task(int x,int y,new Function(int x,int y)
{
    return x+(3/y)+5;
});

所以我必须能够将我在运行时创建的函数作为代码放入我的任务参数中。我有一个Function类。有什么建议吗?

2 个答案:

答案 0 :(得分:2)

我只是谷歌搜索Java令牌评估器,结果出现了:

此博客文章是了解Reverse Polish Notation (RPN)的绝佳资源。帖子包含一些代码,我在下面重构过。我已经移动了代码,使事情更容易理解。

您只需要解析令牌并将它们放在堆栈上。然后,通过从堆栈中弹出项目直到您点击操作符来评估表达式,然后您将评估已弹出的所有项目。

我在评估者中添加了支持xy变量的逻辑。

完整代码示例

ExpressionDriver.java

package math;

public class ExpressionDriver {
    public static void main(String[] args) {
        String expression = "x + ( 3 / y ) + 5";
        double x = 8;
        double y = 3;
        Double result = evaluate(expression, x, y);

        // x 3 y / + 5 + 14.0
        System.out.println(result);
    }

    public static Double evaluate(String expression, double x, double y) {
        String[] tokens = expression.split("[ ]+");
        String[] output = ExpressionParser.infixToRPN(tokens);

        // Build output RPN string minus the commas
        for (String token : output) {
            System.out.print(token + " ");
        }

        // Feed the RPN string to RPNtoDouble to give result
        return ExpressionParser.RPNtoDouble(output, x, y);
    }
}

ExpressionParser.java

package math;
import java.util.ArrayList;
import java.util.Stack;

public class ExpressionParser {
    // Test if token is an operator
    private static boolean isOperator(String token) {
        return Operator.lookup(token) != null;
    }

    // Test associativity of operator token
    private static boolean isAssociative(String token, int type) {
        Operator op = Operator.lookup(token);

        if (op == null) {
            throw new IllegalArgumentException("Invalid token: " + token);
        }

        if (op.getAssociativity() == type) {
            return true;
        }

        return false;
    }

    // Compare precedence of operators.
    private static final int cmpPrecedence(String token1, String token2) {
        Operator op1 = Operator.lookup(token1);
        Operator op2 = Operator.lookup(token2);

        if (op1 == null || op2 == null) {
            throw new IllegalArgumentException("Invalid tokens: " + token1 + " " + token2);
        }

        return op1.getPrecedence() - op2.getPrecedence();
    }

    // Convert infix expression format into reverse Polish notation
    public static String[] infixToRPN(String[] inputTokens) {
        ArrayList<String> out = new ArrayList<String>();
        Stack<String> stack = new Stack<String>();

        // For each token
        for (String token : inputTokens) {
            // If token is an operator
            if (isOperator(token)) {
                // While stack not empty AND stack top element is an operator
                while (!stack.empty() && isOperator(stack.peek())) {
                    if ((isAssociative(token, Operator.LEFT_ASSOC) && cmpPrecedence(token, stack.peek()) <= 0)
                            || (isAssociative(token, Operator.RIGHT_ASSOC) && cmpPrecedence(token, stack.peek()) < 0)) {
                        out.add(stack.pop());
                        continue;
                    }
                    break;
                }
                // Push the new operator on the stack
                stack.push(token);
            }
            // If token is a left bracket '('
            else if (token.equals(Token.OPEN_PAREN)) {
                stack.push(token);
            }
            // If token is a right bracket ')'
            else if (token.equals(Token.CLOSED_PAREN)) {
                while (!stack.empty() && !stack.peek().equals(Token.OPEN_PAREN)) {
                    out.add(stack.pop());
                }
                stack.pop();
            }
            // If token is a number
            else {
                out.add(token);
            }
        }

        while (!stack.empty()) {
            out.add(stack.pop());
        }

        return out.toArray(new String[out.size()]);
    }

    public static double RPNtoDouble(String[] tokens, double x, double y) {
        Stack<String> stack = new Stack<String>();

        // For each token
        for (String token : tokens) {
            // If the token is a value push it onto the stack
            if (!isOperator(token)) {
                stack.push(token);
            } else {
                // Token is an operator: pop top two entries
                Operator op = Operator.lookup(token);
                Double d2 = getDouble(stack.pop(), x, y);
                Double d1 = getDouble(stack.pop(), x, y);
                Double result = op.getExpression().evaluate(d1, d2);

                // Push result onto stack
                stack.push(String.valueOf(result));
            }
        }

        return Double.valueOf(stack.pop());
    }

    public static Double getDouble(String token, double x, double y) {
        if (token.equals("x")) {
            return x;
        } else if (token.equals("y")) {
            return y;
        } else {
            return Double.valueOf(token);
        }
    }
}

Operator.java

package math;

import java.util.HashMap;
import java.util.Map;

public enum Operator {
    ADDITION(Token.PLUS, 0, Operator.LEFT_ASSOC, new Expression() {
        @Override
        public double evaluate(double a, double b) {
            return a + b;
        }
        @Override
        public int evaluate(int a, int b) {
            return a + b;
        }
        @Override
        public float evaluate(float a, float b) {
            return a + b;
        }
    }),
    SUBTRACTION(Token.DASH, 0, Operator.LEFT_ASSOC, new Expression() {
        @Override
        public double evaluate(double a, double b) {
            return a - b;
        }
        @Override
        public int evaluate(int a, int b) {
            return a - b;
        }
        @Override
        public float evaluate(float a, float b) {
            return a - b;
        }
    }),
    MULTIPLICATION(Token.ASTERISK, 5, Operator.LEFT_ASSOC, new Expression() {
        @Override
        public double evaluate(double a, double b) {
            return a * b;
        }
        @Override
        public int evaluate(int a, int b) {
            return a * b;
        }
        @Override
        public float evaluate(float a, float b) {
            return a * b;
        }
    }),
    DIVISION(Token.SLASH, 5, Operator.LEFT_ASSOC, new Expression() {
        @Override
        public double evaluate(double a, double b) {
            return a / b;
        }
        @Override
        public int evaluate(int a, int b) {
            return a / b;
        }
        @Override
        public float evaluate(float a, float b) {
            return a / b;
        }
    });

    // Associativity constants for operators
    protected static final int LEFT_ASSOC = 0;
    protected static final int RIGHT_ASSOC = 1;

    private static final Map<String, Operator> LOOKUP_MAP;

    static {
        LOOKUP_MAP = new HashMap<String, Operator>();

        for (Operator operator : Operator.values()) {
            LOOKUP_MAP.put(operator.getSign(), operator);
        }
    }

    private String sign;
    private int precedence;
    private int associativity;
    private Expression expression;

    private Operator(String sign, int precedence, int associativity, Expression expression) {
        this.sign = sign;
        this.precedence = precedence;
        this.associativity = associativity;
        this.expression = expression;
    }

    public static Operator lookup(String operator) {
        return LOOKUP_MAP.get(operator);
    }

    public String getSign() {
        return sign;
    }

    public int getPrecedence() {
        return precedence;
    }

    public int getAssociativity() {
        return associativity;
    }

    public Expression getExpression() {
        return expression;
    }
}

Expression.java

package math;

public interface Expression {
    int evaluate(int a, int b);

    double evaluate(double a, double b);

    float evaluate(float a, float b);
}

Token.java

package math;

public class Token {
    public static final String PLUS = "+";
    public static final String DASH = "-";
    public static final String ASTERISK = "*";
    public static final String SLASH = "/";

    public static final String OPEN_PAREN = "(";
    public static final String CLOSED_PAREN = ")";
}

答案 1 :(得分:0)

我想你可能想要研究一些表达式语言评估器。一些常见的选择:

MVEL

Groovy

SPel (if you are using Spring)

有很多类似表达式语言的选择,你甚至可以考虑像上面提到的Groovy这样的脚本引擎,或Python,Ruby,Javascript(通过Jython,JRuby等)。简而言之,您可以做的是,向表达式评估引擎提供表达式字符串以及您希望表达式“看到”的相关数据。将相应地评估结果。