Null проверяет наличие сложной цепочки разыменований в Java 8

#java-8 #nullpointerexception #optional

#java-8 #исключение nullpointerexception #необязательно

Вопрос:

Итак, у меня есть класс, созданный некоторым контрактом (поэтому изменения не допускаются) с несколькими уровнями данных, я получаю его через запрос soap, а затем в моем бэкэнде у меня есть что-то вроде этого:

 value = bigRequest.getData().getSamples().get(0).getValuableData().getValue()
 

и при каждом разыменовании в этой цепочке я могу получить нулевой результат. Сам класс не имеет логики, просто чистые данные с аксессорами, но тем не менее. Мне немного надоело думать о создании уродливого шаблона не-нулевых проверок для каждого отдельного разыменования, поэтому я думаю о наилучшей практике здесь:

  1. На самом деле создайте уродливый шаблон (либо с помощью ifs, либо с помощью asserts). Я предполагаю, что это то, что я должен сделать, но у меня слабые надежды.
  2. Выполните некоторую необязательную магию. Но без доступа к изменению исходного кода это, вероятно, будет еще уродливее.
  3. Перехватите NPE. Это некрасиво по своей сути, но в данном конкретном случае я считаю, что это лучший вариант, просто потому, что это часть логики, либо у меня есть это значение, либо нет. Но перехват NPE заставляет меня дрожать.
  4. Что-то, чего я сейчас не вижу сам.

На самом деле я чувствую себя немного неловко из-за этого вопроса, потому что я чувствую, что тема 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 вызова.