Рубрики
Без рубрики

Согласованная обработка нулевых значений в Java

Используйте Опцию / Необязательно везде. Помечено как java, lang, учебное пособие, для начинающих.

Обработка значений null часто считается слабым местом в Java. Для этого есть несколько причин.

Наиболее часто упоминаемая проблема – известное NullPointerException , хотя нет четкого обоснования, почему это является проблемой. В конце концов, это всего лишь признак проблемы, но не сама проблема.

Реальная проблема гораздо глубже. Те, у кого есть опыт написания кода на C или C++, знают этот вопрос гораздо лучше. При написании кода на C/C++ инженер всегда должен иметь в виду бесчисленные нюансы, связанные с безопасностью доступа, неопределенным поведением, выделением памяти, копированием/перемещением объектов и так далее и тому подобное. Все эти многочисленные детали создают постоянное “давление”, потребляют драгоценные ресурсы мозга инженера и приводят к замедлению скорости разработки. Даже закоренелые сторонники C/C++ не могут отрицать этот факт.

Аналогичная проблема существует с null значениями в Java.

Java часто считается многословным языком. Это правда. Это обратная сторона его очевидности. Почти каждое намерение в Java может быть (и обычно есть) явно выражено в коде. Добавляя некоторый дополнительный текст, мы, в свою очередь, получаем сразу доступный контекст, который не нужно держать в голове при чтении Java-кода. Значения null нарушают это правило. Они не проявляются в коде.

Значения null могут появляться по разным причинам. Это может быть инициализация по умолчанию, значение, возвращаемое из какого-либо метода, или даже явно присвоенное значение null . Имея в виду, что иногда null Может появиться , проверка документации метода или кода на возможность возврата такого значения – все это создает “давление”, очень похожее на описанное выше для C/C++.

Что можно сделать для решения этой проблемы? Как устранить это постоянное “давление”, которое влияет на нашу производительность?

Конечно, есть несколько способов решить эту проблему. Мы можем:

  • Добавить @NotNull ( или аналогичные) аннотации. Не делает, по сути, ничего, кроме добавления некоторого (ложного) ощущения, что значения null каким-то образом обрабатываются.
  • Установите строгие правила и проверяйте каждое значение, которое потенциально может быть null . Это рабочее решение, но за счет загрязнения кода бесчисленными проверками null . И, что ж, никто не идеален, мы можем совершать ошибки, и компилятор нам не поможет.
  • Придумайте свой собственный язык. Авторы Kotlin сделали именно это. Опять же, это рабочее решение, но, как по мне, это перебор. Тем не менее, у него есть одна важная вещь: типы с нулевым и ненулевым значением различны и четко выражены в коде.
  • Используйте подходы к функциональному программированию – Может быть, монада в какой-то форме.

Последний пункт – это то, что я собираюсь обсудить более подробно.

Необязательно: хороший, плохой, уродливый

Введено в Java 8 Необязательный класс предназначен для обработки отсутствующих значений вместо null . В какой-то степени это Java-реализация Возможно, монада (но не полностью, см. Ниже).

В то время как некоторые могут рассматривать это как просто причудливый способ работы со значениями null , на самом деле у него есть гораздо более важное преимущество: явное выражение намерения. Как только вы обернете поле, параметр или переменную в Необязательно вы сразу же делаете свое намерение явным и понятным для читателя. Другими словами – вы добавляете этот недостающий контекст. В то же время компилятор начинает видеть разницу, вы больше не одиноки.

Итак, используя Optional инженер убивает трех зайцев одним выстрелом:

  • Делает потенциально отсутствующее значение явным в коде и устраняет “давление” со стороны читателя.
  • Позволяет компилятору контролировать доступ к значению.
  • Делает обработку значений null удобной.

К сожалению Необязательный имеет свои собственные проблемы.

Как упоминалось выше, Необязательная “в некоторой степени” реализация Может быть, монада. Он ссылается на императивный мир и имеет внешне доступную ценность. Вызвав метод get() , вы можете попытаться получить его. Но если вы это сделаете, это может вызвать исключение NullPointerException . Что противоречит целевому назначению Необязательного – be безопасного контейнера для потенциального null (т.е. отсутствующие) значения.

Возможно, именно поэтому некоторые умные головы предполагают, что “использование Optional для полей и параметров является плохой практикой”, а инструменты статического анализа показывают предупреждения о таком использовании Optional .

Решением может быть написание вашей собственной версии Может быть, и использовать его вместо этого. Существует несколько различных реализаций. Я использую one из моей библиотеки Reactive Toolbox Core .

Резюме

Необязательный / Вариант / Возможно, позволяет инженерам Java использовать следующее соглашение:

  • Каждая переменная/поле/параметр с простым типом не является null и никогда не может быть.
  • Каждая переменная/поле/параметр, тип которых заключен в Необязательный / Вариант / Возможно, – потенциально может быть пустым.
  • Если какая-либо внешняя библиотека/вызов может возвращать нулевое значение, результат должен быть немедленно завернут в Необязательно / Вариант / Может быть .

Без каких-либо дополнительных усилий строгое следование приведенному выше соглашению позволяет писать Java-код, который:

  • никогда не вызывает NullPointerException и все значения null обрабатываются должным образом.
  • четко и явно различает нулевые и ненулевые значения в коде и позволяет компилятору применять это различие во время компиляции.

Оригинал: “https://dev.to/siy/consistent-null-values-handling-in-java-3c5e”