Является ли оператор switch самым быстрым способом реализации интерпретации операторов в Java? - PullRequest
2 голосов
/ 23 марта 2010

Является ли оператор switch самым быстрым способом реализации интерпретации оператора в Java

   public boolean accept(final int op, int x, int val) {
     switch (op) {
        case OP_EQUAL:
          return x == val;
        case OP_BIGGER:
          return x > val;
        case OP_SMALLER:
          return x < val;
        default:
          return true;
     }
   }

В этом простом примере, очевидно, да. Теперь представьте, что у вас 1000 операторов. это все еще будет быстрее, чем иерархия классов? Есть ли порог, когда иерархия классов становится более эффективной по скорости, чем оператор switch? (в памяти явно нет)

abstract class Op {
 abstract public boolean accept(int x, int val);
}

И затем один класс на оператора.

EDIT: Извините, я должен был быть более конкретным с точки зрения ответов. Оператор полностью неизвестен, и я использую JDk 1.4. Нет выбора. Нет перечислений. Нет закрытий. :( Оператор выбирается пользователем среди множества вариантов. Для простоты представьте список GUI с 1000 операциями, когда пользователь выбирает один, выбирается код операции оператора switch. Используя иерархию классов, пользователь выбирает класс. Я задаю этот вопрос, потому что кто-то должен был проверить это раньше. Мне не хочется создавать 1000 классов и 1000 поддельных операционных кодов, чтобы проверить это. Если никто этого не сделал. Я протестирую его и сообщу о результатах, если они вообще могут иметь какое-либо значение.

Ответы [ 7 ]

9 голосов
/ 23 марта 2010

EDIT:

Хорошо, так как вы должны использовать JDK 1.4, мой первоначальный ответ - «нет» (ниже для справки). Я бы предположил , что switch не так быстр, как абстрактное решение на основе классов, когда вы просто смотрите на вызов apply(which,a,b) против which.apply(a,b). Вам просто нужно это проверить.

Тем не менее, при тестировании вы также можете учитывать время запуска, объем памяти и т. Д.

ОРИГИНАЛ:

public enum OPERATION {
  // ...operators+implementation, e.g.:
  GREATER_THAN { public boolean apply(int a, int b) { return a > b; } };
  public abstract boolean apply(int a, int b);
}

использование:

OPERATION x = //..however you figure out which
boolean result = x.apply(a,b);

это один из , который использует в Effective Java для перечислений. Он работает точно так же, как switch, только менее запутанно.

8 голосов
/ 23 марта 2010

Из-за способа, которым оператор switch обычно реализуется в jvm с таблицей поиска, скорее всего, он будет быстрее с небольшим или большим количеством операторов. Это просто догадка; чтобы получить определенный ответ, вам нужно сравнить его с системой, для которой он предназначен.

Но это всего лишь микрооптимизация , о которой вам не стоит беспокоиться, если только профилирование не покажет, что оно действительно может изменить ситуацию. Использование целых чисел вместо определенного класса (или перечисления) делает код менее читабельным. Огромное заявление переключателя с 1000 случаями - признак плохого дизайна. И это будет влиять на код, который использует операторы; менее читабельно, больше ошибок, сложнее рефакторировать , ...

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

2 голосов
/ 23 марта 2010

Я не знаю, что быстрее, и я не думаю, что есть какие-либо гарантии. Оптимизация кода очень сильно зависит как от компилятора, так и от времени выполнения.

Я думаю , что трудно опровергнуть утверждение о смене. Из-за ограничений, которые Java накладывает на типы, которые можно переключать, ее довольно легко можно скомпилировать в справочную таблицу, что обеспечивает самый быстрый доступ, который вы можете получить.

1 голос
/ 23 марта 2010

Используйте табличный метод, как указывал предыдущий автор, вы можете использовать оператор в качестве индекса массива. Значение, хранящееся в массиве, может быть экземпляром класса, который выполняет сравнение. Массив можно инициализировать статически или лучше по требованию (ленивый шаблон загрузки).

, например

// Interface and classes
interface Operator {
      boolean operate(int x, int y); 
}

class EqualsOperator implements Operator {
      boolean operate(int x, int y){
        return x==y;
      }
}
class NotEqualsOperator implements Operator {
      boolean operate(int x, int y){
        return x=!y;
      }
}
...

// Static initialization
Operator[] operators = new Operator[n];
operator[0] = new EqualsOperator();
operator[1] = new NotEqualsOperator();
...

// Switch
public boolean accept(final int op, int x, int val) {
    operator[op].operate(x,val);
}
0 голосов
/ 23 марта 2010

Я всегда обнаруживал, что оператор переключения Java не так силен, как мне нужно. В своем последнем выпуске lambdaj реализует его с умным использованием замыкания и совпадения Hamcrest.

0 голосов
/ 23 марта 2010

Я бы не смотрел на это чисто с точки зрения производительности, но оценил бы это как кандидата на рефакторинг, см. c2: Refactor Mercilessly . Мне понравился ответ, полученный на повторяемости кода :

  1. Если вы повторите это один раз, скопируйте его.
  2. Если вы повторите это дважды, рефакторинг.

Я бы определил добавление нескольких операторов в качестве повторения, а затем я бы рефакторинг для реализации Шаблон стратегии .
Я бы назвал классы операторов суффиксом стратегии и реализовал бы метод execute.

0 голосов
/ 23 марта 2010

Если вызывающий метод уже должен решить, какое значение оператора использовать, и вызвать accept (), то самым быстрым будет выполнение встроенных сравнений в этом же вызывающем методе.

В качестве альтернативы используйте три метода (или стратегии):

public boolean acceptGreater(int x, int val) {
   return x > val;
}

public boolean acceptLess(int x, int val) {
   return x < val;
}

public boolean acceptEquals(int x, int val) {
   return x == val;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...