2012-01-17 5 views
9

Скажем, у меня есть цикл, как это:Условия в циклах, передовой практике?

for (int i = 0; i < someint; i++) 
{ 
    if (i == somecondition) 
    { 
     DoSomething(); 
     continue; 
    } 
    doSomeOtherStuff(); 
} 

Versus ...

for (int i = 0; i < someint; i++) 
{ 
    if (i == somecondition) 
    { 
     DoSomething(); 
    } 
    else 
    { 
     doSomeOtherStuff(); 
    } 
} 

Есть ли какой-либо причине, чтобы использовать один над другим? Или это просто личное предпочтение?
Основным языком, на который я прошу это, является Java, но, я думаю, это относится и к большинству других.

+1

Довольно уверен, что компилятор будет оптимизировать как и они будут иметь то же самое представление. – talnicolas

+1

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

+1

Если предложение 'if' является коротким, а предложение' else' дольше, я бы использовал первую форму. –

ответ

16

Технически, нет, но я нахожу второй красивее для этого конкретного случая.

+3

Согласен, кажется более читаемым ИМХО. –

2

Я бы предпочел второй синтаксис.

Старайтесь избегать операторов продолжения, где это возможно. Это делает код путь более трудно следовать, и для этого трудно отлаживать

7

Я предпочитаю второй конструкт ...

for (int i = 0; i < someint; i++) 
{ 
    if (i == somecondition) 
    { 
     DoSomething(); 
     //lets say lot of code 
     //.. 
     //... 
     //... 
     //... 
     continue; 
    } 
    else 
    { 
     doSomeOtherStuff(); 
    } 
} 

Допустим, у вас было много кода перед continue. Это сразу бросается в глаза, просто посмотрев

else 
    { 
     doSomeOtherStuff(); 
    } 

тем он не выполняется безоговорочно.

+3

+1: В ответе, который уже был удален, член с 40k + точками репутации пропустил оператор 'continue'. Я думаю, что это довольно сильный показатель, который даже с относительно коротким выражением if/else опытные программисты все еще могут его пропустить. Блок else делает это намного яснее. – StriplingWarrior

5

Для меня, это зависит от того, что раскол между then и относительной else ветви размеров: если один массово больше, чем другие, и тем меньше из них представляет собой логически исключительную ситуацию, я ставлю короче один в then, и добавьте continue; когда они примерно равны, как по размеру, так и по логическому потоку, я держу их в своих собственных ветвях then и else.

for (String tok : tokens) { 
    if (isKeyword(tok)) { 
     output.write(tok); 
     continue; 
    } 
    // Do some massive processing of non-keyword tokens here 
    // This block goes on... 
    // and on... 
    // and on... You get the idea 
} 

против

for (String op : operators) { 
    if (isAdditive(op)) { 
     // Do something for additive ops 
    } else { 
     // Do something for non-additive ops 
    } 
} 
+1

Если этот блок включен и продолжается, пришло время реорганизовать его в отдельную функцию (или несколько функций). –

+1

@JamesKanze Не обязательно так: если выясняется, что обработка уникальна для этого блока, использует локали, определенные за пределами 'for', и не имеет шансов на повторное использование, нет смысла создавать функцию листа с одним вызовом сайт. Несмотря на то, что есть добавленная возможность дать хорошее имя этому блоку кода, комментарии делают с ним хорошую работу, как перенос кода в отдельную функцию. – dasblinkenlight

+0

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

1

В данном конкретном случае, я согласен со всеми остальными, что второй является предпочтительным. Но бывают случаи, когда я пойду первым. Если DoSomething() действительно были только одним вызовом, а i == someCondition - это кромка края, а doSomeOtherStuff() были на самом деле 20 строк кода вместо этого одного вызова, тогда я бы предпочел использовать continue. В этом сценарии я прочитал его как «во-первых, давайте позаботимся об этом случае с одним краем. Хорошо, теперь давайте сделаем настоящий материал».

Конечно, можно было бы аргументировать if-else, перефразировав мою интерпретацию на «если мы в краевом случае делаем это, а то и делаем реальные вещи». Но это означает, что все эти 20 строк в настоящее время одно гнездое глубже, и для меня более читаемо сначала позаботиться о краевых случаях, а затем сосредоточиться на общем пути.

+0

Если 'doSomeOtherStuff()' 20 строк кода, он должен быть в отдельной функции. –

+0

@JamesKanze Может быть, может и нет. Если цикл 'for' - это единственное, что происходит в функции, например, не может быть причины иметь' myFunction() {for (...) {myActualFunction(); }} '. И, возможно, эти 20 строк не являются 20 заявлениями, но включают в себя множество «вертикальных шумов» (например, метод с длинными аргументами, которые вы разделили на несколько строк). Или комментарии. Дело в том, что это решение. – yshavit

2

Как все говорят, рекомендуется вторая форма. Многие стандарты кодирования рекомендуют вам избегать операторов «продолжить» и «разбить», поскольку это добавляет сложности вашему коду.

Просто чтобы дать вам ссылку:

JSF ++ (Правило 190) и Мишр C (Правило 57) говорят:

продолжените заявление не должен быть использован.

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

Мишра платный, но JSF ++ можно скачать бесплатно здесь:

http://www.jsf.mil/downloads/documents/JSF_AV_C++_Coding_Standards_Rev_C.doc

Это на C++, но многие правила могут быть применены и к другим языкам. Это стоит чтения!

+2

Неиспользование continue неизбежно приведет к ненужному раздуванию кода, поскольку вы вынуждены вручную реализовывать логику продолжения (вероятно, через логические переменные). –

+0

@ edA-qamort-ora-y Вы должны прочитать стандарт, чтобы использовать его. Вначале он делает разницу между употреблением слов «воля», «должен» и «должен». Правила «должны» - это рекомендации, которые следует использовать, когда это возможно. Но, если вы не работаете со старыми кодами, вы редко не сможете избежать «продолжения». –

+1

@ edA-qamort-ora-y Почти 30 лет опыта я никогда не видел такого случая. За исключением случаев, когда функция была слишком сложной для начала, в этом случае решение состоит в том, чтобы реорганизовать ее на более мелкие функции, а не добавлять к сложности уже слишком сложной функции. –

0

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

Скажет, например, у вас есть много, и я имею в виду много условий внутри вашего цикла, где, имея много if заявлений на самом деле влияет на читаемость через отступ:

for (int i = 0 ; i < n ; i++) 
{ 
    if (obj[i]) 
    { 
     doSomething(); 
     if (someOtherCondition() 
     { 
      //........... 
                if (/* some levels down */) 
                { 

                } 
      //..... 
     } 
    } 
} 

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

Таким образом, вы можете реорганизовать и сделать его намного более читаемым с:

for (int i = 0 ; i < n ; i++) 
{ 
    if (!obj[i]) 
    { 
     continue; 
    } 
    doSomething(); 
    if (!someOtherCondition() 
    { 
     continue; 
    } 
    //........... 
} 
0

Я думаю, что это в большей степени зависит от того, что вы делаете.

Это простой пример, но, как правило, если есть условие, что я «извлечение» из другой логики цикла, я вытащу его как можно быстрее с продолжением, а не с добавлением к сложности будущее, если заявления (ваш первый пример, если это условие, которое может быть извлечено упрощение будущей логики) например:

for (int i = 0 ; i < n ; i++) 
{ 
    if(obj[i] != null && obj[i].instanceOf("A")) { 
     doSomething(); 
    } else if(obj[i] != null && obj[i].instanceOf("B"){ 
     doSomethingElse(); 
    } 
} 

сейчас стало ясно, что извлекая первое условие в

if(obj[i] == null) { 
    continue; 
} 

может сохранить некоторую путаницу так как этот цикл будет усилен. Я часто использую эту тактику для тестирования параметров метода и возвращаюсь раньше или бросаю исключение.

Также (это полностью отвлеченный, а не часть ответа вообще!), Я бы сказал, что если вы когда-нибудь увидите сбалансированное состояние «Truly», вы можете серьезно подумать о своем дизайне OO. Если йоЗотеЬЫпд и someOtherCondition было то, что похожи, они, вероятно, следует различных реализаций метода определенной в базовом классе или интерфейсе, что приводит к этому коду:

for (int i = 0 ; i < n ; i++) 
{ 
    obj[i].doSomething(); 
}