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