![Приемы и советы. Как избежать 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.
Оригинал
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Спасибо автору!