Отлов NullPointerException
- действительно проблематичное занятие, поскольку оно может произойти практически где угодно. Очень легко получить один из бага, поймать его случайно и продолжить, как будто все в порядке, тем самым скрывая реальную проблему. С этим так сложно справиться, поэтому лучше избегать его вообще. (Например, подумайте об автоматической распаковке нуля Integer
.)
Я предлагаю вам использовать Optional
вместо этого класс. Часто это лучший подход, когда вы хотите работать с ценностями, которые либо присутствуют, либо отсутствуют.
Используя это, вы можете написать свой код следующим образом:
public Optional<Integer> m(Ws wsObject) {
return Optional.ofNullable(wsObject.getFoo()) // Here you get Optional.empty() if the Foo is null
.map(f -> f.getBar()) // Here you transform the optional or get empty if the Bar is null
.map(b -> b.getBaz())
.map(b -> b.getInt());
// Add this if you want to return null instead of an empty optional if any is null
// .orElse(null);
// Or this if you want to throw an exception instead
// .orElseThrow(SomeApplicationException::new);
}
Почему необязательно?
Использование Optional
s вместо null
значений, которые могут отсутствовать, делает этот факт очень заметным и понятным для читателей, а система типов гарантирует, что вы случайно не забудете об этом.
Вы также получаете доступ к методам для более удобной работы с такими значениями, например, map
и orElse
.
Отсутствие действительно или ошибка?
Но также подумайте, является ли это допустимым результатом для промежуточных методов, возвращающих ноль, или это признак ошибки. Если это всегда ошибка, то, вероятно, лучше создать исключение, чем возвращать специальное значение, или чтобы сами промежуточные методы генерировали исключение.
Может еще варианты?
Если, с другой стороны, действительны отсутствующие значения из промежуточных методов, может быть, вы также можете переключиться на Optional
s для них?
Тогда вы можете использовать их так:
public Optional<Integer> mo(Ws wsObject) {
return wsObject.getFoo()
.flatMap(f -> f.getBar())
.flatMap(b -> b.getBaz())
.flatMap(b -> b.getInt());
}
Почему не по желанию?
Единственная причина, по которой я могу не использовать, Optional
- это если это действительно критичная для производительности часть кода, и если накладные расходы на сборку мусора оказываются проблемой. Это происходит потому , что несколько Optional
объектов выделяются каждый раз , когда код выполняется, и виртуальная машина может не быть в состоянии оптимизировать те прочь. В этом случае ваши оригинальные if-тесты могут быть лучше.
null
чеков, так какwsObject.getFoo().getBar().getBaz().getInt()
это уже запах кода. Прочтите, что такое «Закон Деметры» , и предпочтите соответственно реорганизовать свой код. Тогдаnull
исчезнет и проблема с чеками. И подумайте об использованииOptional
.