是否可以将算术运算符传递给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);

是否要预定义这些BinaryOperators(或在某处声明为常量)更多的是一种风格选择。

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中的方法?的主要内容,如果未能解决你的问题,请参考以下文章

Java中的算术运算符

是否可以计算 R 中的算术运算次数?

第五篇 JAVA运算符

JAVA-初步认识-第二章-算术运算符2

shell脚本中的算术运算和条件测试语句

Python中的算术运算符都有哪些呢?