Преимущество переключения оператора if-else - PullRequest
157 голосов
/ 19 сентября 2008

Как лучше всего использовать оператор switch по сравнению с использованием оператора if для перечислений 30 unsigned, где около 10 имеют ожидаемое действие (в настоящее время это то же самое действие). Производительность и пространство необходимо учитывать, но это не критично. Я абстрагировал фрагмент, поэтому не ненавидите меня за соглашения об именах.

switch оператор:

// numError is an error enumeration type, with 0 being the non-error case
// fire_special_event() is a stub method for the shared processing

switch (numError)
{  
  case ERROR_01 :  // intentional fall-through
  case ERROR_07 :  // intentional fall-through
  case ERROR_0A :  // intentional fall-through
  case ERROR_10 :  // intentional fall-through
  case ERROR_15 :  // intentional fall-through
  case ERROR_16 :  // intentional fall-through
  case ERROR_20 :
  {
     fire_special_event();
  }
  break;

  default:
  {
    // error codes that require no additional action
  }
  break;       
}

if оператор:

if ((ERROR_01 == numError)  ||
    (ERROR_07 == numError)  ||
    (ERROR_0A == numError)  || 
    (ERROR_10 == numError)  ||
    (ERROR_15 == numError)  ||
    (ERROR_16 == numError)  ||
    (ERROR_20 == numError))
{
  fire_special_event();
}

Ответы [ 23 ]

1 голос
/ 19 сентября 2008

Они работают одинаково хорошо. Производительность примерно такая же, как у современного компилятора.

Я предпочитаю, чтобы операторы были вместо операторов case, потому что они более читабельны и более гибки - вы можете добавлять другие условия, не основанные на числовом равенстве, такие как "|| max

1 голос
/ 19 сентября 2008

Если ваши дела, вероятно, останутся сгруппированными в будущем - если более одного дела соответствуют одному результату - коммутатор может оказаться проще для чтения и обслуживания.

1 голос
/ 19 сентября 2008

Я не уверен насчет наилучшей практики, но я бы использовал switch - и затем ловил бы намеренный провал через 'default'

1 голос
/ 01 октября 2010
while (true) != while (loop)

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

1 голос
/ 25 сентября 2008

Эстетически я склоняюсь к такому подходу.

unsigned int special_events[] = {
    ERROR_01,
    ERROR_07,
    ERROR_0A,
    ERROR_10,
    ERROR_15,
    ERROR_16,
    ERROR_20
 };
 int special_events_length = sizeof (special_events) / sizeof (unsigned int);

 void process_event(unsigned int numError) {
     for (int i = 0; i < special_events_length; i++) {
         if (numError == special_events[i]) {
             fire_special_event();
             break;
          }
     }
  }

Сделайте данные немного умнее, чтобы мы могли сделать логику немного тупее.

Я понимаю, это выглядит странно. Вот вдохновение (из того, как я это сделал в Python):

special_events = [
    ERROR_01,
    ERROR_07,
    ERROR_0A,
    ERROR_10,
    ERROR_15,
    ERROR_16,
    ERROR_20,
    ]
def process_event(numError):
    if numError in special_events:
         fire_special_event()
1 голос
/ 19 сентября 2008
Переключатель

определенно предпочтителен. Проще посмотреть список дел коммутатора и точно знать, что он делает, чем читать длинное условие if.

Дублирование в состоянии if плохо сказывается на глазах. Предположим, что один из == был написан !=; вы заметили? Или, если один экземпляр 'numError' был написан 'nmuError', который только что скомпилировался?

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

Что касается производительности, лучше всего использовать профилировщик для измерения производительности вашего приложения в условиях, которые аналогичны тем, которые вы ожидаете в дикой природе. В противном случае вы, вероятно, оптимизируете не в том месте и не в том направлении.

0 голосов
/ 23 ноября 2009

Я знаю его старое, но

public class SwitchTest {
static final int max = 100000;

public static void main(String[] args) {

int counter1 = 0;
long start1 = 0l;
long total1 = 0l;

int counter2 = 0;
long start2 = 0l;
long total2 = 0l;
boolean loop = true;

start1 = System.currentTimeMillis();
while (true) {
  if (counter1 == max) {
    break;
  } else {
    counter1++;
  }
}
total1 = System.currentTimeMillis() - start1;

start2 = System.currentTimeMillis();
while (loop) {
  switch (counter2) {
    case max:
      loop = false;
      break;
    default:
      counter2++;
  }
}
total2 = System.currentTimeMillis() - start2;

System.out.println("While if/else: " + total1 + "ms");
System.out.println("Switch: " + total2 + "ms");
System.out.println("Max Loops: " + max);

System.exit(0);
}
}

Изменение количества циклов сильно меняется:

Хотя if / else: 5 мс Переключатель: 1 мс Макс. Петли: 100000

Хотя if / else: 5 мс Переключатель: 3 мс Макс. Петли: 1000000

Пока if / else: 5 мс Переключатель: 14 мс Макс. Петли: 10000000

Пока if / else: 5 мс Переключатель: 149мс Макс. Петли: 100000000

(добавьте больше заявлений, если хотите)

0 голосов
/ 19 сентября 2008

Я бы выбрал утверждение if для ясности и условности, хотя я уверен, что некоторые не согласятся. В конце концов, вы хотите что-то сделать if некоторые условия выполняются! Наличие переключателя с одним действием кажется немного ... ненужным.

0 голосов
/ 19 сентября 2008

Пожалуйста, используйте переключатель. Оператор if займет время, пропорциональное количеству условий.

0 голосов
/ 19 сентября 2008

Я не тот человек, кто расскажет вам о скорости и использовании памяти, но смотреть на состояние переключателя - чертовски легче понять, чем большой оператор if (особенно через 2-3 месяца)

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