Можно ли передать арифметические операторы в метод в Java? - PullRequest
26 голосов
/ 25 мая 2010

Прямо сейчас мне нужно написать метод, который выглядит следующим образом:

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?

Ответы [ 8 ]

36 голосов
/ 25 мая 2010

Нет, вы не можете сделать это в 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));
9 голосов
/ 25 мая 2010

Аргументы метода в Java должны быть выражениями. Оператор сам по себе не является выражением. Это невозможно в Java.

Конечно, вы можете передавать объекты (возможно, enum константы), которые представляют эти операторы, и действовать соответственно, но вы не можете передавать сами операторы в качестве параметров.


Дополнительные советы

Так как вы только начинаете Java, лучше внедрить эту информацию на ранних стадиях, чтобы облегчить ваше будущее развитие.

  • Имена методов начинаются со строчной буквы: calculate вместо Calculate
  • Имена переменных начинаются со строчной буквы: operator вместо Operator
  • Double - ссылочный тип, поле для примитивного типа double.
    • Effective Java 2nd Edition, Item 49: Предпочтение типов примитивов примитивам в штучной упаковке
  • Не return "error...". Вместо throw new IllegalArgumentException("Invalid operator");

Смотри также

4 голосов
/ 25 мая 2010

Существует только громоздкий способ сделать это с помощью интерфейса обратного вызова. Что-то вроде

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) );
}

Вы также можете использовать enum вместо интерфейса, если вам нужно только меньшее фиксированное количество операторов.

3 голосов
/ 25 мая 2010

Вы не можете передавать операторов напрямую. Вы можете использовать функторы .

public double Calculate(BinaryFunction<Double, Double, Double> op, double Operand1, double Operand2)
{
  return (double)op.evaluate(Operand1, Operand2);
}
2 голосов
/ 25 мая 2010

Вы можете либо

  1. Используйте функциональный язык для JVM для реализации этой части вашего кода (clojure, scala et el), оберните лямбда-функции вокруг математических операторов и передайте эти функции в качестве параметров

  2. Получите оценщик выражений для Java, например http://www.singularsys.com/jep/ (а также должно быть много бесплатных альтернатив)

1 голос
/ 25 мая 2010

Было бы неплохо, не так ли? Но вы просто не можете этого сделать. Вы, вероятно, можете сделать нечто подобное, написав свои собственные «операторы».

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 .

1 голос
/ 25 мая 2010

Нет, это невозможно.

Вам понадобится парсер, чтобы делать то, что вы хотите, и это может быть громоздким.

Вы, вероятно, задаете не тот вопрос,поскольку вы получаете неправильный ответ.

Если вы ищете математический синтаксический анализатор, вы можете взглянуть на этот проект на SF: http://sourceforge.net/projects/jep/

Там могут быть некоторые ответы вэто.

0 голосов
/ 25 мая 2010

Операторы, AFAIK, не могут быть переданы в качестве параметра на любом языке (по крайней мере, я встречал это).

Причина в том, что в качестве «значений для параметров» могут передаваться только значения (либо путем копирования, либо по ссылкам).

И операторы не представляют значений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...