应用在java中作为字符串发现的运算符的最优雅方式?

LB4*_*B40 5 java

潜在的愚蠢:假设我有一个包含运算符的字符串,应用此运算符的最佳方法是什么?

我倾向于做的是:

if(n.getString(1).equals("<<")) {
  result = tmp1 << tmp2;
}
Run Code Online (Sandbox Code Playgroud)

对于我所拥有的每种运营商.有没有更好的办法 ?

mis*_*tor 15

不确定你是否称之为优雅,但这是一种方式:

interface Operation {
  int apply(int a, int b);
}

Map<String, Operation> operations = new HashMap<String, Operation>() {{
  put("+", new Operation() { public int apply(int a, int b) { return a + b; }});
  put("-", new Operation() { public int apply(int a, int b) { return a - b; }});
  put("*", new Operation() { public int apply(int a, int b) { return a * b; }});
  put("<<", new Operation() { public int apply(int a, int b) { return a << b; }});
  // some more operations here
}};
Run Code Online (Sandbox Code Playgroud)

然后你可以用以下代码替换你的if声明

result = operations.get(n.getString(1)).apply(tmp1, tmp2);
Run Code Online (Sandbox Code Playgroud)


Car*_*arl 7

可以这样做:

enum Operator {

 BITSHIFT { ... }, ADD { ... }, XOR { ... }, //...etc

 Operator public static which(String s) { //...return the correct one
 }

 public abstract int apply(int a, int b); //...defined explicitly for each enum

}
Run Code Online (Sandbox Code Playgroud)

一旦switch语句转到Strings ,返回正确的一个将是非常好的.

此解决方案如下所示(Operator.如果使用静态导入,则为sans ):

 int result = Operator.which(s).apply(a,b);
Run Code Online (Sandbox Code Playgroud)

但我会选择其他人经过广泛测试和使用过的解析器.


Edw*_*uck 5

面向对象的方法是使用可能操作的枚举.这样每个操作只能消耗内存中的一个对象.

public enum Operation {


  ADD() {
    public int perform(int a, int b) {
      return a + b;
    }
  },
  SUBTRACT() {
    public int perform(int a, int b) {
      return a - b;
    }
  },
  MULTIPLY() {
    public int perform(int a, int b) {
      return a * b;
    }
  },
  DIVIDE() {
    public int perform(int a, int b) {
      return a / b;
    }
  };

  public abstract int perform(int a, int b);

}
Run Code Online (Sandbox Code Playgroud)

要调用此类代码,您可以执行以下操作:

int result = Operation.ADD(5, 6);
Run Code Online (Sandbox Code Playgroud)

然后你可以创建一个Strings to Operations的映射,如下所示:

Map<String, Operation> symbols = new Map<String, Operation>();
symbols.put("+", Operation.ADD);
symbols.put("-", Operation.SUBTRACT);
symbols.put("/", Operation.DIVIDE);
symbols.put("*", Operation.MULTIPLY);
...
Run Code Online (Sandbox Code Playgroud)

最后,要使用这样的系统:

symbols.get(n.getString(1).apply(tmp1, tmp2));
Run Code Online (Sandbox Code Playgroud)

以这种方式使用枚举的一个优点是,如果您选择这样做,您可以轻松地比较数据上的操作

Operation operation = symbols.get("*");
if (operation != Operation.MULTIPLY) {
  System.out.println("Foobar as usual, * is not multiply!");
}
Run Code Online (Sandbox Code Playgroud)

此外,您获得了所有操作的集中位置,唯一的缺点是Operation.java文件可能会随着足够大的运算符集而变大.

长期可能存在的唯一问题是,虽然这样的系统很有用且易于阅读和理解,但它确实没有考虑优先级.假设您的公式都按优先顺序进行评估,这样的问题无关紧要.按优先顺序表达公式的示例可以在反向波兰表示法,波兰表示法等中找到.

优先级重要的是当您被允许表达以下项目时:

4 + 5 * 2
Run Code Online (Sandbox Code Playgroud)

根据典型的惯例,5*2应该在4 + 5之前进行评估.处理优先级的唯一正确方法是在内存中形成一个评估树,或者保证所有输入都以简单,明确的方式处理优先级(波兰表示法,反向波兰表示法等).

我假设您知道优先级问题,但是感谢您让我提及它,以便那些尚未编写此类代码的人受益.