Чистый код. Создание, анализ и рефакторинг (Мартин) - страница 89

Легко сказать, что проблемы в приведенном коде возникли из-за пропущенной проверки null. В действительности причина в другом: этих проверок слишком много. Если у вас возникает желание вернуть null из метода, рассмотрите возможность выдачи исключения или возвращения объекта «особого случая». Если ваш код вызывает метод стороннего API, способный вернуть null, создайте для него обертку в виде метода, который инициирует исключение или возвращает объект особого случая.

Довольно часто объекты особых случаев легко решают проблему. Допустим, у вас имеется код следующего вида:

>List employees = getEmployees();

>if (employees != null) {

>  for(Employee e : employees) {

>    totalPay += e.getPay();

>  }

>}

Сейчас метод getEmployees может возвращать null, но так ли это необходимо? Если изменить getEmployee так, чтобы метод возвращал пустой список, код станет чище:

>List employees = getEmployees();

>for(Employee e : employees) {

>  totalPay += e.getPay();

>}

К счастью, в Java существует метод Collections.emptyList(), который возвращает заранее определенный неизменяемый список, и мы можем воспользоваться им для своих целей:

>public List getEmployees() {

>  if( .. there are no employees .. )

>    return Collections.emptyList();

>}

Такое решение сводит к минимуму вероятность появления NullPointerException, а код становится намного чище.

Не передавайте null

Возвращать null из методов плохо, но передавать null при вызове еще хуже. По возможности избегайте передачи null в своем коде (исключение составляют разве что методы сторонних API, при вызове которых без нее не обойтись).

Следующий пример поясняет, почему не следует передавать null. Возьмем простой метод для вычисления метрики по двум точкам:

>public class MetricsCalculator

>{

>  public double xProjection(Point p1, Point p2) {

>    return (p2.x — p1.x) * 1.5;

>  }

>  …

>}

Что произойдет, если при вызове будет передан аргумент null?

>calculator.xProjection(null, new Point(12, 13));

Конечно, возникнет исключение NullPointerException.

Как исправить его? Можно создать новый тип исключения и инициировать его в методе:

>public class MetricsCalculator

>{

>  public double xProjection(Point p1, Point p2) {

>    if (p1 == null || p2 == null) {

>      throw InvalidArgumentException(

>        "Invalid argument for MetricsCalculator.xProjection");

>    }

>    return (p2.x — p1.x) * 1.5;

>  }

>}

Стало лучше? Пожалуй, лучше, чем NullPointerException, но вспомните: для InvalidArgumentException приходится определять обработчик. Что должен делать этот обработчик? Возьметесь предложить хорошую идею?