是否可以将算术运算符传递给java中的方法?
Posted
技术标签:
【中文标题】是否可以将算术运算符传递给java中的方法?【英文标题】:Is it possible to pass arithmetic operators to a method in java? 【发布时间】:2011-02-23 13:15:44 【问题描述】:现在我将不得不编写一个如下所示的方法:
public String Calculate(String operator, double operand1, double operand2)
if (operator.equals("+"))
return String.valueOf(operand1 + operand2);
else if (operator.equals("-"))
return String.valueOf(operand1 - operand2);
else if (operator.equals("*"))
return String.valueOf(operand1 * operand2);
else
return "error...";
如果我能把代码写成这样就好了:
public String Calculate(String Operator, Double Operand1, Double Operand2)
return String.valueOf(Operand1 Operator Operand2);
因此运算符将替换算术运算符(+、-、*、/...)
有谁知道在java中这样的事情是否可行?
【问题讨论】:
【参考方案1】:不,你不能在 Java 中做到这一点。编译器需要知道您的操作员在做什么。你可以做的是一个枚举:
public enum Operator
ADDITION("+")
@Override public double apply(double x1, double x2)
return x1 + x2;
,
SUBTRACTION("-")
@Override public double apply(double x1, double x2)
return x1 - x2;
;
// You'd include other operators too...
private final String text;
private Operator(String text)
this.text = text;
// Yes, enums *can* have abstract methods. This code compiles...
public abstract double apply(double x1, double x2);
@Override public String toString()
return text;
然后你可以写一个这样的方法:
public String calculate(Operator op, double x1, double x2)
return String.valueOf(op.apply(x1, x2));
然后这样称呼它:
String foo = calculate(Operator.ADDITION, 3.5, 2);
// Or just
String bar = String.valueOf(Operator.ADDITION.apply(3.5, 2));
【讨论】:
枚举不能有抽象方法。 +1,但在减法实现和第二个参数的标识符中有错字。 @aioobe:是的,我刚刚得到了标识符,但错过了实现。 @Ashsish:是的,如果所有值都覆盖它,他们可以。 这解决了我的问题!感谢您分享您的解决方案。在 Python 这样的动态编程语言中,会有一个 eval() 方法来拯救,但在 Java 中没有。 @KennyMeyer 在 Python 中不会使用邪恶的eval()
,而是将 operator
模块中的函数作为参数传递。 def calculate(op, a, b): return op(a, b)
和被称为 calculate(operator.add, 3.5, 2)
。【参考方案2】:
Java 中的方法参数必须是表达式。运算符本身不是表达式。这在 Java 中是不可能的。
当然,您可以传递代表这些运算符的对象(可能是enum
常量)并采取相应的行动,但您不能将运算符本身作为参数传递。
其他提示
由于您刚刚开始使用 Java,因此最好尽早掌握这些信息以简化您未来的开发。
方法名称以小写开头:calculate
而不是Calculate
变量名以小写开头:operator
而不是Operator
Double
是一个引用类型,原始类型 double
的框。
Effective Java 2nd Edition,Item 49:Prefer Primitive types to boxed primitive
不要return "error..."
。相反,throw new IllegalArgumentException("Invalid operator");
另见
Java Language Guide/Autoboxing Java Lessons/Exceptions Coding Conventions/Naming 不幸的是,本文档中有错字:How is this statement making sense? (Sun’s naming convention for Java variables)【讨论】:
【参考方案3】:只有使用回调接口的繁琐方法。类似的东西
interface Operator
public Double do(Double x, Double y);
然后你实现你需要的操作符:
Operator plus = new Operator()
public Double do(Double x, Double y)
return x + y;
;
你的通用方法需要一个运算符和两个参数:
public String Calculate(Operator operator, Double x, Double y)
return String.valueOf( operator.do(x, y) );
如果您只需要较小的固定数量的运算符,您也可以使用枚举而不是接口。
【讨论】:
可能比较麻烦,但这比使用枚举要灵活和可扩展。 就是这样。特别是因为您可以将匿名类用于一次性运算符。 @Daniel:是的,这取决于您是否有一组固定的运算符。如果你这样做了,枚举会更整洁 IMO(并允许序列化等)。如果您需要额外的灵活性,匿名内部类位可以正常工作。当然,你总是可以创建一个实现接口的枚举,以获得两全其美:) @Jon:确实如此。这就是为什么我没有说这种方法一定更好,只是说它“更加灵活和可扩展”。在许多情况下,“灵活和可扩展”等于更好,但显然并非总是如此。 (序列化是一个很好的反例,顺便说一句。)它只是表明你不应该选择你的设计,直到你知道问题的约束!【参考方案4】:您不能直接传递运算符。你可以使用functors。
public double Calculate(BinaryFunction<Double, Double, Double> op, double Operand1, double Operand2)
return (double)op.evaluate(Operand1, Operand2);
【讨论】:
【参考方案5】:你可以
使用 JVM 的函数式语言来实现这部分代码(clojure、scala 等),将 lambda 函数包装在数学运算符周围并将这些函数作为参数传递
获取 Java 表达式评估器,例如 http://www.singularsys.com/jep/(并且必须有许多免费的替代品)
【讨论】:
【参考方案6】:不,这是不可能的。
你需要一个解析器来做你想做的事,这可能很麻烦。
你可能问错了问题,因为你得到了错误的答案。
如果您正在寻找数学解析器,您可能想看看 SF 上的这个项目:http://sourceforge.net/projects/jep/
这里面可能有一些答案。
【讨论】:
【参考方案7】:这会很好,不是吗?但是,你就是不能那样做。您可能可以通过编写自己的“运算符”来完成类似的事情。
public interface Operator
Double calculate(Double op1, Double op2);
public Addition implements Operator
@Override
Double calculate(Double op1, Double op2) return op1 + op2;
public class Calculator
private static Operator ADDITION = new Addition();
private static Map<String,Operator> OPERATORS = new HashMap<String,Operator>();
static
OPERATORS.put("+",ADDITION);
public String Calculate(String operator, Double operand1, Double operand2)
return String.valueOf(OPERATORS.get(operator).calculate(operand1,operand2);
您了解如何将其扩展到许多其他运算符......显然不仅仅是双精度数。我的方法的优点是您实际上可以保留接受 String 运算符的方法签名。
【讨论】:
【参考方案8】:自从在 Java 8 中引入了lambda expressions 和functional interfaces,你可以更地道地做到这一点。
public static <T> T calculate(BinaryOperator<T> operator, T operand1, T operand2)
return operator.apply(operand1, operand2);
是否要预定义这些BinaryOperator
s(或在某处声明为常量)更多的是一种风格选择。
Integer r1 = calculate((a, b) -> a + b, 2, 2); // 4
Integer r2 = calculate(Integer::sum, 2, 2); // 4
【讨论】:
【参考方案9】:运算符,AFAIK,不能以任何语言作为参数传递(至少我遇到过)。
原因是只有值(通过复制或通过引用)可以作为“值到参数”传递。
并且运算符不代表任何值。
【讨论】:
运算符可以在我知道的每一种函数式语言中作为参数传递。 Scala 可以在 JVM 上完成。 是的,当我读到那部分时,我内心有点死了。传递运算符的能力是面向 Java 的人从未考虑过的事情之一,然后他们找到了一种支持它的语言,并希望它让他们大吃一惊 @Daniel:这告诉我研究 Scala :) 无论如何,运算符的东西不适用于 Java ;)以上是关于是否可以将算术运算符传递给java中的方法?的主要内容,如果未能解决你的问题,请参考以下文章