🎉 Нужна клёвая книга о паттернах на русском? Вот она »

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

Также известен как: 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]
До
getValueForPeriod(periodNumber: number): number {
  try {
    return values[periodNumber];
  } catch (ArrayIndexOutOfBoundsException e) {
    return 0;
  }
}
После
getValueForPeriod(periodNumber: number): number {
  if (periodNumber >= values.length) {
    return 0;
  }
  return values[periodNumber];
}

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

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

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

Достоинства

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

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

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

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

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

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