潜在的愚蠢:假设我有一个包含运算符的字符串,应用此运算符的最佳方法是什么?
我倾向于做的是:
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)
可以这样做:
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)
但我会选择其他人经过广泛测试和使用过的解析器.
面向对象的方法是使用可能操作的枚举.这样每个操作只能消耗内存中的一个对象.
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之前进行评估.处理优先级的唯一正确方法是在内存中形成一个评估树,或者保证所有输入都以简单,明确的方式处理优先级(波兰表示法,反向波兰表示法等).
我假设您知道优先级问题,但是感谢您让我提及它,以便那些尚未编写此类代码的人受益.