【问题标题】:Is it possible to pass arithmetic operators to a method in java?是否可以将算术运算符传递给java中的方法?
【发布时间】:2021-06-07 02:30:04
【问题描述】:

现在我将不得不编写一个如下所示的方法:

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中这样的事情是否可行?

【问题讨论】:

    标签: java operators math


    【解决方案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");

    另见

    【讨论】:

      【解决方案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】:

        你可以

        1. 使用 JVM 的函数式语言来实现这部分代码(clojure、scala 等),将 lambda 函数包装在数学运算符周围并将这些函数作为参数传递

        2. 获取 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 expressionsfunctional 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 ;)
                猜你喜欢
                • 1970-01-01
                • 2011-10-17
                • 2015-02-06
                • 2017-09-30
                • 1970-01-01
                • 1970-01-01
                • 2022-12-10
                • 1970-01-01
                相关资源
                最近更新 更多