#java-8 #nullpointerexception #optional
#java-8 #исключение nullpointerexception #необязательно
Вопрос:
Итак, у меня есть класс, созданный некоторым контрактом (поэтому изменения не допускаются) с несколькими уровнями данных, я получаю его через запрос soap, а затем в моем бэкэнде у меня есть что-то вроде этого:
value = bigRequest.getData().getSamples().get(0).getValuableData().getValue()
и при каждом разыменовании в этой цепочке я могу получить нулевой результат. Сам класс не имеет логики, просто чистые данные с аксессорами, но тем не менее. Мне немного надоело думать о создании уродливого шаблона не-нулевых проверок для каждого отдельного разыменования, поэтому я думаю о наилучшей практике здесь:
- На самом деле создайте уродливый шаблон (либо с помощью ifs, либо с помощью asserts). Я предполагаю, что это то, что я должен сделать, но у меня слабые надежды.
- Выполните некоторую необязательную магию. Но без доступа к изменению исходного кода это, вероятно, будет еще уродливее.
- Перехватите NPE. Это некрасиво по своей сути, но в данном конкретном случае я считаю, что это лучший вариант, просто потому, что это часть логики, либо у меня есть это значение, либо нет. Но перехват NPE заставляет меня дрожать.
- Что-то, чего я сейчас не вижу сам.
На самом деле я чувствую себя немного неловко из-за этого вопроса, потому что я чувствую, что тема NPE изучена досконально, но у меня не было успеха в поиске.
Комментарии:
1. Я не думаю, что цепочка
map
выглядит настолько уродливо:Optional.ofNullable(bigRequest).map(RequestCls::getData).map(DataCls::getSamples).map(samples -> samples.get(0)).map(SampleCls::getValuableData).map(ValDataCls::getValue)
2. @andrew-vershinin это красиво, тем не менее, это не работает =) Но на данный момент я не уверен, зависит ли это от конкретной коллекции. Итак, у меня есть null at
map(DataCls::getSamples)
, а следующая карта приводит к исключению IndexOutOfBoundsException, поэтому оно, вероятно, работает в целом, но требует специальной логики для списков. Мне нужна моя утренняя доза кофеина, тогда я смогу быть более объективным.3. 5. Остановите поведение возврата
null
.4. @AndrewVershinin, добавление .filter(samples -> samples.size() > 0) также сработало. Добавьте это в качестве ответа, чтобы я мог его принять.
5. Другой вариант — переписать некоторые части вашего кода на других языках JVM, таких как Kotlin или Groovy, которые имеют нулевой оператор ‘?’. Например, в Kotlin ваш код будет выглядеть так
bigRequest.getData()?.getSamples()?.getOrNull(0)?.getValuableData()?.getValue()
, что он полностью безопасен для null
Ответ №1:
Я согласен с вами обоими, что предложение Эндрю Вершинина — лучшее, что мы можем здесь сделать, и, следовательно, заслуживает публикации в качестве ответа.
nullableValue = Optional.ofNullable(bigRequest)
.map(RequestCls::getData)
.map(DataCls::getSamples)
.filter(samples -> ! samples.isEmpty())
.map(samples -> samples.get(0))
.map(SampleCls::getValuableData)
.map(ValDataCls::getValue)
.orElse(null);
Вам нужно будет заменить правильные имена классов или интерфейсов в ссылках на методы (или вы можете переписать как лямбды, если хотите). Редактировать: если bigRequest
сам по себе не может быть null
, первый вызов метода должен быть просто Optional.of(bigRequest)
.
Это не основное предназначение Optional
, но я нахожу это нормальным. И лучше, чем пункты 1. и 3. (и 4.) из вашего вопроса.
Комментарии:
1. Единственное предостережение — это накладные расходы памяти из-за
Optional
создания экземпляра внутри каждогоOptional#map
вызова.