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

код:

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

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

16 ответов


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

для моей точки зрения, 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;
}

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


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

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

оставил позади вопрос, как это читается для начинающих.

ссылки

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

обзоры вопросы


Это зависит от многих вещей, как сложный код. С помощью простого примера, подобного этому, я бы поставил возврат на ту же строку, что и ifs, и не использовал 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;
}

если функция имеет несколько "успешных" возвращаемых значений, я буду использовать 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 в таких случаях могут стать уродливыми. Самое важное предостережение при таком подходе заключается в том, что любой код очистки для ранних выходов должен быть задан явно, или же для обеспечения очистки необходимо использовать функцию-оболочку.


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


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

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

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 ....
     */
  }
}

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


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

  }
}

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


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

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

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

Я могу думать о преимуществе elses. Если вы хотите добавить новый последний случай, без elses вы можете забыть добавить if к текущему "слишком горячему состоянию", если вы хотите добавить "Умираю" в 120 или около того. в то время как с elses вы знаете, что вам нужно, чтобы финал еще был перед "умиранием", поэтому вы, скорее всего, подумаете о том, чтобы положить еще, если перед "слишком жарко". Также, если вы просто поставите еще на "умирание", вы получите ошибку компиляции, которая заставляет вас думать.


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

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

это типичный стиль предложения guard, который я лично и сообщество 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";
}

конечно, так как это is в основном таблица сопоставления, вы можете также реализовать ее как карта:

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

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

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

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

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

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

...
if (temp < 35)
{
  foo.status = TOO_COLD;
  return;
}
else
{
  foo.status = TEMP_OKAY;
}
launch_the_rocket(now);
return;

Я согласен, что elses делает это более ясным. Финал else особенно помогает провести визуальное различие между случаем, когда каждая ветвь имеет возврат, и случаями, когда только некоторые ветви имеют возврат (который может быть запахом).


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


кто использует IF / ELSE IF... когда вы можете использовать оператор SWITCH?

Я предпочитаю один оператор RETURN-несколько операторов return могут сделать отладку болью...


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

поэтому аргумент является одиночным или составным оператором.

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

PS. Я бы всегда отправлял температуру в градусах по Цельсию, ой, просто нарушил вашу функцию!


это хорошо. без "еще", эта строка

if(temp < 80)
    return "Comfortable";

будет неубедительно. с "другом", понятно, что есть и другие предпосылки.


Я предпочитаю высказывания case сам, но это сделало бы это языковой конкретной темой, а не языковой агностической темой.

    Dim Temp As Integer
    Dim Message As String

    Select Case Temp
        Case Is < 32
            Message = "Freezing"
        Case Is < 60
            Message = "Just Right"
        Case Is < 80
            Message = "Too Hot"
        Case Else
            Message = "What was I doing?"
    End Select

Я нахожу их намного легче читать, чем если..еще заявления.