Также известен как Replace Exception with Test

Рефакторинг Замена исключения проверкой условия

Проблема

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

Решение

Замените выбрасывание исключения проверкой этого условия.
До
double getValueForPeriod(int periodNumber) {
  try {
    return values[periodNumber];
  } catch (ArrayIndexOutOfBoundsException e) {
    return 0;
  }
}
После
double getValueForPeriod(int periodNumber) {
  if (periodNumber >= values.length) {
    return 0;
  }
  return values[periodNumber];
}
До
double GetValueForPeriod(int periodNumber) 
{
  try 
  {
    return values[periodNumber];
  } 
  catch (IndexOutOfRangeException e) 
  {
    return 0;
  }
}
После
double GetValueForPeriod(int periodNumber) 
{
  if (periodNumber >= values.Length) 
  {
    return 0;
  }
  return values[periodNumber];
}
До
function getValueForPeriod($periodNumber) {
  try {
    return $this->values[$periodNumber];
  } catch (ArrayIndexOutOfBoundsException $e) {
    return 0;
  }
}
После
function getValueForPeriod($periodNumber) {
  if ($periodNumber >= count($this->values)) {
    return 0;
  }
  return $this->values[$periodNumber];
}
До
def getValueForPeriod(periodNumber):
    try:
        return values[periodNumber]
    except IndexError:
        return 0
После
def getValueForPeriod(self, periodNumber):
    if periodNumber >= len(self.values):
        return 0
    return self.values[periodNumber]

Причины рефакторинга

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

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

Достоинства

  • Простой условный оператор иногда может быть очевиднее блока обработки исключения.

Порядок рефакторинга

  1. Создайте условный оператор для граничного случая и поместите его перед try/catch блоком.

  2. Переместите код из catch-секции внутрь этого условного оператора.

  3. В catch-секции поставьте код выбрасывания обычного безымянного исключения и запустите все тесты.

  4. Если никаких исключений не было выброшено во время тестов, избавьтесь от оператора try/catch.

Устали читать?

Сбегайте за подушкой, у нас тут контента на 7 часов чтения.

Или попробуйте наш новый интерактивный курс по рефакторингу. Он более информативный и гораздо более интересный, чем банальный текст.

Узнать больше...

Живой пример

Первый раз здесь? Ничего страшного!

У нас здесь всё просто – интерактивный пример очень похож на видео (но выглядит гораздо круче).

  1. После начала проигрывания, вам показываются разнообразные подсказки и сообщения. Вы продвигаетесь дальше, кликая на них.
  2. Вы можете перематывать шаги, используя стрелки слева.
  3. Кроме того, вы можете посмотреть разницу между первоначальным и получившимся кодом, нажав кнопку с глазом ().
  4. Кнопка компиляции () позвоялет проверить текущий код на наличие ошибок.