Предпочтение программирования - использовать else ifs с несколькими операторами возврата? - PullRequest
9 голосов
/ 27 августа 2010

Код:

public String getTemperatureMessage(double temp)
{
    if(temp < 32)
        return "Freezing";
    else if(temp < 60)
        return "Brr";
    else if(temp < 80)
        return "Comfortable";
    else
        return "Too hot";
}

Что касается приведенного выше фрагмента кода, остальные if технически излишни и совсем не меняют поведение.Тем не менее, я, как правило, хотел бы разместить их там, чтобы подчеркнуть, что условия являются исключительными.о чем ты думаешь?Ненужное или более понятное?

Ответы [ 16 ]

10 голосов
/ 27 августа 2010

Единственная возможная альтернатива в этом частном случае - захватить условный оператор ?:.

public String getTemperatureMessage(double temp) {
    return temp < 32 ? "Freezing"
         : temp < 60 ? "Brr"
         : temp < 80 ? "Comfortable"
         : "Too hot";
}

. Остался вопрос, как это можно прочитать для начинающих.

Ссылки

  • JLS 15.25 Условный оператор ?:
    • Оператор является ассоциативным справа, поэтому такое вложение оператора будет работать "как ожидалось"

Смежные вопросы

9 голосов
/ 27 августа 2010

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

public String getTemperatureMessage(double temp)
{
    if(temp < 32) return "Freezing";
    if(temp < 60) return "Brr";
    if(temp < 80) return "Comfortable";
    return "Too hot";
}

Когда у меня есть более сложный код, я считаю полезным не вырываться из вложенности с возвратами или продолжить / прерывать, а назначать переменным состояния или результата. Затем я также включу {}, даже если блок является одним оператором, главным образом для сохранения согласованности в том, как структура представлена ​​в коде, но также для небольшого уменьшения риска того, что последующие изменения забудут изменить оператор на блок.

Если бы этот пример был более сложным, я бы, вероятно, написал его так:

public String getTemperatureMessage(double temp) {
    String result;
    if(temp < 32) {
        result = "Freezing";
    } else {
        if(temp < 60) {
            result = "Brr";
        } else {
            if(temp < 80) {
                result = "Comfortable";
            } else {
                result = "Too hot";
            }
        }
    }
    return result;
}
8 голосов
/ 27 августа 2010

Если функция имеет несколько «успешных» возвращаемых значений, я буду использовать if / else для выбора среди них. Если функция имеет нормальное возвращаемое значение, но один или несколько способов, которые могут ненормально завершиться рано, я обычно не буду использовать «else» для нормального пути. Например, я думаю, что гораздо более «естественно» сказать:

int do_something(int arg1)
{
  if (arg1 > MAX_ARG1_VALUE)
    return ARG1_ERROR;
  ... main guts of code here
  return 0;
}

чем сказать:

int do_something(int arg1)
{
  if (arg1 > MAX_ARG1_VALUE)
    return ARG1_ERROR;
  else
  {
    ... main guts of code here
    return 0;
  }
}

или

int do_something(int arg1)
{
  if (arg1 <= MAX_ARG1_VALUE)
  {
    ... main guts of code here
    return 0;
  }
  else
    return ARG1_ERROR;

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

int do_something(int arg1)
{
  if (arg1 > MAX_ARG1_VALUE)
    return ARG1_ERROR;
  ... some code goes here
  if (something_went_wrong1)
    return SOMETHING1_ERROR;
  ... more code goes here
  if (something_went_wrong2)
    return SOMETHING2_ERROR;
  ... more code goes here
  if (something_went_wrong3)
    return SOMETHING3_ERROR;
  return 0;
}

Вложенные операторы if / else в таких случаях могут быть ужасными. Самым важным предупреждением при таком подходе является то, что любой код очистки для ранних выходов должен быть задан явно, или же для обеспечения очистки должна использоваться функция-обертка.

7 голосов
/ 27 августа 2010

Кто-то скажет, что проблема с возвращением множества будет здесь.Но это не совсем моя точка зрения.

На мой взгляд, if / else if действительно важен, потому что даже если в вашем случае вы вернете какое-то значение, удаление elses будет означать, что вы не поместитеих в любом случае, и это означало бы совершенно другое, если бы здесь не было результатов.

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

public String getTemperatureMessage(double temp){
    String message;
    if(temp < 32)
        message = "Freezing";
    if(temp < 60)
        message = "Brr";
    if(temp < 80)
        message = "Comfortable";
    else 
        message = "Too hot";
    return message;
}

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

2 голосов
/ 27 августа 2010

Для простых однострочных я склонен пропустить else, но если есть более сложные if блоки, я предпочитаю else, чтобы прояснить, что условия являются взаимоисключающими.

1 голос
/ 02 ноября 2011

Излишние эльсы заставляют меня съеживаться.Дополнительный синтаксис и отступы затрудняют чтение.Я только что удалил кучу этих из некоторого кода, который я унаследовал.

В большинстве случаев избыточный код является ошибкой, так что с другой стороны, избыточный «else» выглядит для меня ошибкой, даже если вы положили его туда.цель.У меня сложилось впечатление о коде, который был изначально написан без встроенных возвратов, затем кто-то переписал его, чтобы иметь встроенные возвраты, но им было лень убирать остальные.

Единственный if / return легко понять;так же 4 подряд.Это "тот случай закончен; давайте двигаться дальше".Длинная цепочка if / elses может быть трудной для чтения;вам нужно прочитать все до конца, прежде чем вы узнаете, что происходит.Изящество экономии в том, что оно позволяет использовать один возврат - функция, которая переоценена в IMO, но я признаю, что она действительно обеспечивает определенную ценность.Однако длинная цепочка if / elses в сочетании с доходностями, смешанными среди elses, является худшим из обоих миров - со всеми недостатками множественных возвратов, и создана так, чтобы выглядеть как одна большая конструкция, которую вы должны сразу получить в своей голове.Тьфу.

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

Наконец, пример if / return / else приведен к его избыточному выводу.Я видел несколько таких в последнее время.Почему в мире есть еще блок?Код в блоке else выполняется в тех же условиях, что и код непосредственно после него:

...
if (temp < 35)
{
  foo.status = TOO_COLD;
  return;
}
else
{
  foo.status = TEMP_OKAY;
}
launch_the_rocket(now);
return;
1 голос
/ 27 августа 2010

Лично я думаю, что else не нужны. Поскольку этот вопрос помечен как [language-agnostic], я приведу несколько примеров того, как я бы написал:

def temperature_message(temp)
  return 'Freezing'    if temp < 32
  return 'Brr'         if temp < 60
  return 'Comfortable' if temp < 80
  'Too hot'
end

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

def temperature_message(temp)
  case
  when temp < 32
    'Freezing'
  when temp < 60
    'Brr'
  when temp < 80
    'Comfortable'
  else
    'Too hot'
  end
end

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

def temperature_message(temp)
  case temp
  when (-1.0/0.0)...32
    'Freezing'
  when 32...60
    'Brr'
  when 60...80
    'Comfortable'
  else
    'Too hot'
  end
end

Хотя я должен признать, что мне все еще легче читать первое.

Поскольку это в основном таблица сопоставления, я бы попытался отформатировать ее так, чтобы каждый, кто читает код, сразу увидел «таблицу»:

def temperature_message(temp)
  case temp
  when (-1.0/0.0)...32 then 'Freezing'
  when         32...60 then 'Brr'
  when         60...80 then 'Comfortable'
                      else 'Too hot'
  end
end

Это также относится к вашей исходной реализации Java:

public String getTemperatureMessage(double temp) {
    if(temp < 32) return "Freezing";
    if(temp < 60) return "Brr";
    if(temp < 80) return "Comfortable";
    else          return "Too hot";
}

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

def temperature_message(temp)
  {
    (-1.0/0.0)...32       => 'Freezing',
            32...60       => 'Brr',
            60...80       => 'Comfortable',
            80..(1.0/0.0) => 'Too hot'
  }.detect {|range, _| range.include?(temp) }.last
end
1 голос
/ 27 августа 2010

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

<Code>
if (error condition) {  
  do some stuff;
  return;
} else {
  do stuff;
  if (other error condition) {
     do some stuff1;
     return;
  } else {
     do some other stuff;
     return

  }
}
</Code>

Приведенный ниже код снижает уровень вложенности, что снижает сложность кода:


if (error condition) {
  do some stuff;
  return;
}
do stuff;
if (other error condition) {
  do some stuff1;
  return;
}
do some other stuff;
return;

В вашем примере это легко в любом случае. Но во многих случаях вам лучше использовать таблицу поиска для такого рода вещей и читать значения из файла / базы данных. Для эффективности в C часто это кодируется как массив структур.

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

Я могу подумать о преимуществе остальных. Если вы хотите добавить новый последний случай, без других вы можете забыть добавить if в текущее «Too Hot Condition», если, скажем, вы хотите добавить «Dying» на 120 или что-то еще. в то время как с остальными вы знаете, что вам нужно, чтобы финал остался перед «Умиранием», так что вы, скорее всего, подумаете о том, чтобы поставить «остальное» перед «Слишком жарко». Также, если вы просто добавите еще «Dying», вы получите ошибку компиляции, которая заставляет вас думать.

1 голос
/ 27 августа 2010

Для простого оператора if без слишком большого количества строк кода, имеющих несколько возвратов, проблем не возникает.Однако ничто так меня не бесит, как:

function doTemperatureCalculations(double temperature) {
  if (temperature < 20) {
    /* 
      Gazillion lines of code here .....
     */
    return "Very cold!";
  } else if (temperature < 40) {
    /*
      Another gazillion loc .....
     */
    return "Summer in the North Pole.";
  } else {
    /*
      Multiple returns embedded throughout ....
     */
  }
}
1 голос
/ 27 августа 2010
public String getTemperatureMessage(double temp)
{
    String retval = null;
    if(temp < 32)
        retval = "Freezing";
    else if(temp < 60)
        retval = "Brr";
    else if(temp < 80)
        retval = "Comfortable";
    else
        retval = "Too hot";
    return retval;
}
...