JavaRush /Java блог /Архив info.javarush /Приемы и советы. Как избежать NullPointerException в Java...
DarthVictor
28 уровень

Приемы и советы. Как избежать NullPointerException в Java приложениях

Статья из группы Архив info.javarush
Приемы и советы. Как избежать NullPointerException в Java приложениях - 1Сегодня я покажу вам простые приемы того как избежать NullPointerException в ваших приложениях. Им легко следовать, но при этом они заметно повышают надежность и качество вашего кода. Более того, по моему опыту, один первый совет окажет заметное влияние на качество вашего кода. Если вы знаете какие-то еще приемы программирования на Java, не стесняйтесь делиться ими в комментариях. Приемы и советы. Как избежать NullPointerException в Java приложениях - 2

Вызывайте методы equals() и equalsIgnoreCase() у известной строки литерала, а не у неизвестного объекта

Всегда вызывайте метод equals() у известной строки, про которую вы знаете, что она не null. Метод equals() симметричен, то есть вызов a.equals(b) и b.equals(a) даст одинаковый результат (если a и b не null), и по этой причине многие программисты не уделяют внимание тому, у каких объектов вызывается equals(), у a или у b. Одним из побочных эффектов этого становится NullPointerException, в случае если метод вызывается у null.

Object unknownObject = null;

//плохой способ - может вызвать NullPointerException
if(unknownObject.equals("knownObject")){
   System.err.println("This may result in NullPointerException if unknownObject is null");
}

//правильный способ - исключение NullPointerException не возникнет, даже если unknownObject null
if("knownObject".equals(unknownObject)){
    System.err.println("better coding avoided NullPointerException");
}
Это был самый простой совет, как избежать NullPointerException, но он один приводит к громадным улучшениям, поскольку метод equals() встречается повсеместно.

Выбирайте valueOf(), а не toString(), в случаях, когда оба дают один результат

Поскольку вызов toString() у ссылки со значением null вызывает исключение NullPointerException, лучше использовать вызов valueOf(), когда мы можем получить тот же результат, поскольку вызов valueOf() от null возвращает null. Особенно это касается классов оберток, таких как Integer, Float, Double или BigDecimal.

BigDecimal bd = getPrice();
System.out.println(String.valueOf(bd)); //не выбрасывает NPE
System.out.println(bd.toString()); //выбрасывает "Exception in thread "main" java.lang.NullPointerException"
Используйте эти советы, когда не уверены может ли объект быть null или нет.

Используйте null-безопасные методы и библиотеки

Существует множество опенсорсных библиотек, которые берут на себе тяжелое бремя проверки на null. Одна из наиболее распространенных — StringUtils от Apache Commons. Используя такие методы как StringUtils.isBlank(), isNumeric(), isWhiteSpace() и т.д. вы можете не беспокоится о возникновении NullPointerException.

//Методы StringUtils являются null-безопасными, они не вызовут NullPointerException
System.out.println(StringUtils.isEmpty(null));
System.out.println(StringUtils.isBlank(null));
System.out.println(StringUtils.isNumeric(null));
System.out.println(StringUtils.isAllUpperCase(null));
Вывод: true true false false И все же перед использованием, не забудьте прочесть документацию null-безопасных методов и классов. Это еще один из лучших Java приемов, который, не требуя значительных усилий, ведет к огромным улучшениям.

Старайтесь не возвращать null из метода, лучше верните пустую коллекцию

Это еще один хороший совет по программированию на Java, который Джошуа Блох описывает в своей книге "Java. Эффективное программирование". Возвращая пустые коллекции или массивы, убедитесь, что при вызове базовых методов вроде size() или length() не возникнет NullPointerException. В классе Collections специально объявлены удобные реализации пустых списков, множеств и словарей: Collections.EMPTY_LIST, Collections.EMPTY_SET and Collections.EMPTY_MAP. Например:

public List getOrders(Customer customer){
   List result = Collections.EMPTY_LIST;
   return result;
}
Аналогично можно использовать Collections.EMPTY_SET и Collections.EMPTY_MAP вместо того, чтобы возвращать null.

Используйте аннотации @NotNull и @Nullable

В описании ваших методов вы можете определить соглашение null-безопасности методов, используя аннотации @NotNull и @Nullable чтобы показать может метод возвращать null или нет. Современные компиляторы и IDE могут использовать эти аннотации для анализы вашего кода и выдавать соответствующие советы, например, о пропущенной проверке на null, или наоборот, о возможности убрать лишнюю проверку, засоряющую код. Такие аннотации, например, поддерживают IntelliJ IDE и FindBugs, кроме этого они входят в JSR 305. Но даже если ваша IDE и не поддерживает такие аннотации, они сами по себе будут хорошей документацией. Глядя на @NotNull и @Nullable программисту будет проще понять где нужно добавлять проверку на null, а где — нет. Это, кстати, довольно новая среди Java программистов практика, и должно пройти время, чтобы она распространилась.

Избегайте ненужной автоупаковки и автораспаковки в вашем коде

Мало того, что это ведет к созданию лишних временных объектов, автоупаковка еще может вызывать NullPointerException, если класс обертки — null. Например, следующий код "свалится" в NullPointerException, если запись о человеке не содержит телефона и возвращает null.

Person ram = new Person("ram");
int phone = ram.getPhone();
При использовании автоупаковки или автораспаковки не только равенства, но и неравенства <, >> могут приводить к NullPointerException.

Следуйте соглашениям и определяйте разумные значения по-умолчанию.

Один из лучших способов избежать NullPointerException в Java — правильное объявление соглашений о кодировании и следование им. Большинство исключений NullPointerException возникают тогда, когда объект пытаются создать, не обладая всеми необходимыми для него данными и зависимостями. Запретив создание незавершенных объектов, изящно отклоняя подобные запросы, вы избавите себя в будущем от большого числа NullPointerException. Аналогично, если вы разрешаете создание объекта, то вы должны подобрать разумное значение по-умолчанию. Например, объект класса Employee не может быть создан без имени и id, но может не иметь номер телефона. В таком случае у объектов Employee, лишенных номера, вместо null может возвращаться ноль. Хотя подобное поведение объекта стоит заранее продумать — быть может, что проще будет проверить на null, нежели звонить по несуществующему номеру. В таком случае наличие дополнительных условий на то, какие поля null, а какие — нет, поможет принять правильное решение. В целом выбор между немедленным падением программы или присвоением null — это важное решение в проектировании, и сделав выбор вы должны ему последовательно следовать.

Задавайте ограничения на уровне СУБД

Используя базу данных для хранения объектов вашей программы, таких как покупатели (Customers) или заказы (Orders), будет разумно задать "null-овость" ваших объектов на уровне СУБД, при помощи соответствующих ограничений на таблицы. Базы данных часто содержат информацию из разных источников, и введение проверок на пропущенные значения повысит целостность ваших данных. Кроме этого наличие проверок на null на уровне СУБД, уменьшит их в вашем Java коде: загружая данные из БД в Java-объекты, вы можете быть уверены в их наличии и убрать лишние "!= null" из кода программы.

Используйте шаблон Null-объекта

Создание специальных Null-объектов — еще один способ избежать NullPointerExcpetion в Java. Предположим, что какой-то метод в нашем приложении возвращает объект, с которым впоследствии работает программа, вызавая его методы. Например, метод Collection.iterator() возвращает объект класса Iterator, который используется для прохода по коллекции. Тогда если у изначального объекта нет никакого итератора, вместо null можно вернуть специальный Null-объект, у которого есть метод hasNext(), всегда возвращающий false. Вот и все дорогой читатель, на этом я заканчиваю свои советы по избавлению Java программ от ошибок NullPointerException. Вы оцените, на сколько могут быть полезны эти простые и не обременительные правила. Напоминаю, что если вы хотите поделиться какими-то еще приемами по NullPointerException в программах на Java, не стесняйтесь делать это в комментариях. Переведено специально для студентов JavaRush. Оригинал
Комментарии (6)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
1mag1Neee Уровень 41
10 мая 2023
Еще один совет, если метод возвращает один объект, который потенциально может быть null, то оборачиваете его в Optional<yourType>. Эта хорошая практика.
Дмитрий Уровень 39
22 марта 2022
Блестящая статья!
Дмитрий Уровень 24
10 сентября 2020
В полезные закладки!
10 июля 2019
Отличная статья, спасибо!
SlyFox Уровень 22
15 января 2016
Круто, спасибо!
Gradus Уровень 27
27 февраля 2015
Статья летит прямиком в избранное)
Спасибо автору!