Почему "else" редко используется после "if x then return"?

этот метод:

boolean containsSmiley(String s) {
    if (s == null) {
        return false;
    }
    else {
        return s.contains(":)");
    }
}

можно эквивалентно написать:

boolean containsSmiley(String s) {
    if (s == null) {
        return false;
    }

    return s.contains(":)");
}

(связанных с: должна ли функция иметь только один оператор return?)

23 ответов


По моему опыту, это зависит от кода. Если я "охраняю" от чего-то, я сделаю:

if (inputVar.isBad()) {
    return;
}

doThings();

суть ясна: если это утверждение ложно, я не хочу, чтобы функция, чтобы продолжать.

С другой стороны, есть некоторые функции с несколькими параметрами и в этом случае я бы написал так:

if (inputVar == thingOne) {
    doFirstThing();
} else if (inputVar == secondThing) {
    doSecondThing();
} else {
    doThirdThing();
}

хотя это может быть написано как:

if (inputVar == thingOne) {
    doFirstThing();
    return;
}
if (inputVar == thingTwo) {
    doSecondThing();
    return;
}
doThingThree();
return;

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


на else в этом случае будет избыточным, а также создаст ненужный дополнительный отступ для основного кода функции.


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

из ссылки:

double getPayAmount() {
    double result;
    if (_isDead) {
        result = deadAmount();
    } else {
        if (_isSeparated) {
            result = separatedAmount();
        } else {
            if (_isRetired) {
                result = retiredAmount();
            } else {
                result = normalPayAmount();
            }
        }
    }

    return result;
}

используя предложение Guard, вы увидите этот результат:

double getPayAmount() {
    if (_isDead) return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired) return retiredAmount();

    return normalPayAmount();
};

вы увидите это повсюду:

if (condition) {
    return var;
}
// by nature, when execution reaches this point, condition can only be false,
// therefore, the else is unnecessary
return other_var;

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

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

0x00: test [condition]
0x01: if result of test was not true, goto [0x04]
0x02: push [var] onto stack
0x03: goto [0x05]
0x04: push [other_var] onto stack
0x05: return from subroutine

код (опять же, это псевдокод, а не сборка) будет действовать точно так же для if/then/else условное.

многие люди считают плохой и / или запутанной практикой иметь несколько возможных точек выхода для функции, поскольку программист должен думать о каждом возможном пути через свой код. Другая практика заключается в следующем:

return (condition) ? var : other_var;

это упрощает код и не создает никаких новых точек выхода.


Я предпочитаю писать так:

boolean containsSmiley(String s) {
    return s != null && s.contains(":)");
}

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

  1. работает ли код так, как ожидалось во всех ситуациях. (Принцип наименьшего удивления)

  2. может ли следующий разработчик (я или кто-то другой) понять, что он делает и почему.

  3. насколько хрупок код в отношении изменений.

  4. - Это просто, как это должно быть и не более. Т. е. нет над или под инженерией.

Как только я счастлив, что я удовлетворил вышесказанное, остальное, как правило, просто попадает в строку.


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

boolean containsSmiley(String s) {
    assert s != null : "Quit passing null values, you moron.";
    return s.contains(":)");
}

я переключился на общее эмпирическое правило: никогда. Когда-либо. передайте значения null, если внешний API-интерфейс явно не запрашивает его. Во-вторых: если внешний метод может возвращать значения null, замените его разумным ненулевое значение (например, пустая строка) или добавить аккуратную проверку. Меня тошнит от повторений!--1--> проверка.

но это немного оффтоп. Мне нравится ставить короткие условия сверху и охранять предложения, удаляя elses, если поток программ диктует, что он никогда не доберется туда.


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

if (s == null) {
    return false;
}
else if (s.Contains(":))")) {
    return true;
}
else if (s.Contains(":-(")) {
    return false;
}

return s.contains(":)");

Бритва Оккама это принцип, что "сущности не должны умножаться сверх необходимости."


на if оператор проверяет / применяет ваш контракт / ожидание не получения нулевых значений. По этой причине я предпочел бы видеть его отделенным от остальной части функции, поскольку он не имеет ничего общего с фактической логикой того, что вы пытаетесь выполнить (хотя этот случай очень прост).

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


на else избыточна. Также некоторые IDEs (Eclipse) и инструменты анализа (возможно, FindBugs) могут помечать это как предупреждение или ошибку, поэтому в этом случае программисты, вероятно, удалят его.


потому что это приятнее. Вы знаете, что вы также можете использовать " { "' } " для создания нескольких уровней вложенности, но никто не делает этого просто так.


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

в качестве аналогии сравните следующие 2 предложения: "если сегодня идет дождь, то возьмите зонтик, иначе возьмите солнцезащитные очки. и "если сегодня идет дождь, то возьмите зонтик, возьмите солнцезащитные очки". Первое предложение соответствует первому блоку кода от вопроса, второе – второму. Первый гораздо понятнее и понятнее, не так ли?


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


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

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


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


хотя наличие else является правильным, и в нем нет ничего плохого с точки зрения логики и управляемости, мне нравится избегать начального момента WTF, когда функция не имеет оператора return вне области if/else.


Как вы можете видеть, разные люди имеют разные мнения о читаемости. Некоторые люди думают, что меньшее количество строк кода делает код более читаемым. Другие считают, что симметрия второй формы делает ее более читаемой.

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


потому что в eclipse есть необязательное (по умолчанию отключено) предупреждение, если в такой ситуации используется else ;).


Ну, некоторые из причин - просто условность, но есть одно преимущество в форме выше...

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


Я бы предпочел одну точку выхода над несколькими с точки зрения обслуживания. Конечный результат может быть изменен (или оформлен) в одной точке выхода, а не в n точках выхода.


вторая форма, если проще/короче. Это не всегда означает ясность. Я предлагаю вам сделать то, что вы считаете наиболее ясным.. Лично я бы написал.

static boolean containsSmiley(String s) { 
    return s != null && s.contains(":)"); 
} 

потому что это то же самое, что написать одно из следующих, которое приводит доказательства о намерении программиста:

boolean containsSmiley(String s) {
    if (s == null)   // The curly braces are not even necessary as the if contains only one instruction.
        return false;

    return s.contains(":)");
}

или даже так:

boolean constainsSMiley(String s) {
    return string.IsNullOrEmpty(s) ? false : s.Contains(":)");
}

эти две формы являются:

  1. более элегантным;
  2. легче читать;
  3. более худой и быстрый для программиста чтения.