Должен ли я использовать @NotNull и @NonNull вместе? - PullRequest
3 голосов
/ 05 февраля 2020

Я использую javax.validation.constraints.NotNull для гибербата проверки пустых полей. Сейчас я использую lombok для простых кодов конструктора, но мне нужно использовать аннотацию @NonNull, чтобы поле было включено в конструктор обязательных полей. Должен ли я использовать их вместе?

1 Ответ

4 голосов
/ 05 февраля 2020

Существует, по крайней мере, 4 полностью различных последствий того, что делает ненулевая аннотация. Большинство аннотаций подразумевают только одну из этих разных вещей. Поэтому да, может иметь смысл применить более одной такой аннотации. К сожалению, фактическое значение этих аннотаций довольно запутано, потому что, по моему опыту, практически никто из разработчиков не учел тот факт, что они имеют в виду разные вещи; на самом деле большинство разработчиков, с которыми я встречался, совершенно не замечают тот факт, что аннулированные аннотации невероятно сложны и неопределенно определены.

Интерпретация системы типов («не может быть!»)

Эта интерпретация является утверждением типа, которое пытается быть таким же сильным, как String в String x;: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} *} *} * * * * * * * * * * * * * * * * * * * * * * * * * * *. невозможно, естественно, было бы совершенно бесполезной идеей проверить это. Учитывая это объявление, что-то вроде String z = (String) x настолько бесполезно, что на самом деле это предупреждение компилятора.

Так же и с такой аннотацией. Примерами этого являются checkerframework, eclipse и intellij: org.checkerframeworkchecker.nullness.qual.NonNull, org.jetbrains.annotations.NotNull и eclipse's org.eclipse.jdt.annotation.NonNull, все в основном подразумевают это значение (хотя intellij относится к параметрам и методам, тогда как checkerframework и eclipse являются аннотациями type_use. Я говорил вам это сложно: P).

Эти аннотации, подразумевающие «не может быть», используются для проверки во время записи. По той же причине написание String x = 5; является немедленным , так как вы пишете этот код и еще до того, как сохраняете файл, красная волнистая линия подчеркивания в вашей IDE, как и, скажем, someMethod(map.get(key)), где someMethod's параметр аннотируется одной из этих NonNull аннотаций. Это не столько «вы не должны», это «вы не можете этого сделать; я даже не позволю вам».

Конечно, javac компилятор не на самом деле работают именно так, именно IDE и инструменты пытаются сделать так, чтобы это выглядело так. Точно так же, как если бы вы никогда не приводили переменную типа String к String, вы на самом деле не рассматриваете такие аннулирования аннулирования как подразумевающие необходимость проверки. Нет; значит: нет. Это подразумевает, что проверка уже выполнена, и вам не нужно проверять снова.

Конечно, это сложно: танцевать вокруг того факта, что компилятор java на самом деле остановит вас от нарушения смысла эти ненулевые аннотации ... некоторые инструменты (такие как kotlinc) в любом случае будут вставлять явные нуль-проверки. Немного похоже на то, как обобщенные значения могут заставить javac внедрять некоторые проверки типов в местах, где вы никогда не писали явное приведение, чтобы обойти тот факт, что обобщенные элементы являются дополнением времени компиляции для сохранения обратной совместимости. Идея состоит в том, чтобы рассмотреть эти детали реализации, о которых вам не следует думать.

Интерпретация БД

Когда hibernate использует класс в качестве шаблона для создания оператора CREATE TABLE SQL Полезно иметь возможность использовать аннотации для установки ограничений и правил и т.п. По той же причине, по которой вы можете пометить поле следующим образом: «Превращая это в столбец SQL, скажите, чтобы механизм БД поместил в него уникальный индекс», вы можете пометить его как: «При превращении этого в в столбце SQL укажите механизму БД наложить на него ненулевое ограничение ".

Это относится к интерпретации системы типов, как к оружию и бабушке: у вас могут быть объекты, представляющие строки в БД, но которая не будет успешно сохранена из-за нарушения ограничения все время ; например, любое поле unid с автоматическим подсчетом обычно равно 0, и оно не будет таким образом сохраняться (механизм БД преобразует этот 0 в «не имеет значения; вставьте без него и позвольте последовательности механизма БД заполнить это число). Так же и с этими: это действительно ничего не значит для java; механизм SQL позаботится о том, чтобы указать, что вставка / обновление завершается неудачно из-за сбойного ограничения. Конечно, чтобы сохранить туда-обратно в БД и поскольку это просто не разрешено быть простым, большинство фреймворков БД будут иметь нулевую проверку, как вы называете эквивалентом .save() или .store(). Но это всего лишь ярлык для этого ограничения БД.

Интерпретация проверки

Иногда объекты в java представляют собой внешнюю вещь. Например, строка БД (частично совпадающая с предыдущим значением) или, скажем, веб-форма, представленная пользователем. Такие объекты ДОЛЖНЫ представлять точно фактическое состояние фактической внешней вещи, которую оно представляет. Бородавки и недопустимые гобелены и все такое.

И обычно у вас есть фреймворк, который позволяет вам проверить их. Вот что означало бы ненулевое значение проверки: это поле может быть нулевым, и если вы попытаетесь установить его в нулевое значение, исключений не будет (следовательно, они могут быть). Однако, пока это поле остается пустым, если вы спросите меня, является ли объект действительным, ответ будет таким: Нет.

Интерпретация ломбка

К сожалению, ломбок несколько мутит воду ... как и все остальные фреймворки. Что означает ломбок @NonNull, зависит от того, где он появляется. Если для параметра это означает: Lombok, пожалуйста, сгенерируйте явную нулевую проверку в качестве первой строки в методе, если только я сам не написал это.

В полях это означает: "Ради @RequiredArgsConstructor, Считайте это поле обязательным; проверьте его на null (сгенерировав исключение) в сгенерированном конструкторе. Также скопируйте аннотацию nullity, где это уместно, и, следовательно, если для этого поля сделан установщик ... добавьте эту nullcheck внутри. "

Ваш конкретный c case

Учитывая, что аннулированные аннотации означают совершенно разные вещи, поэтому потенциально не безумно применять более одной такой аннотации к одной и той же конструкции в вашем коде. Если вы хотите, чтобы механизм БД генерировал ограничение SQL NON NULL, если этот класс используется в качестве шаблона, и для любого объекта, представляющего строку в этой таблице, немедленно отклонить любая попытка перевести его в недопустимое состояние, добавив оба, может иметь смысл. Если вы предпочитаете, чтобы объекты приемлемо представляли недопустимое состояние, что почти всегда имеет место, если общий принцип заключается в создании пустого объекта и затем установке каждого значения поля по одному с помощью установщика - тогда не добавляйте lombok's аннотация.

Конечно, вы рассмотрели всю сложность, верно?

Даже не проблеск. Для настоящего скручивания мозга рассмотрим checkerframework's @ PolyNull и посчитайте, что это упрощение того, с чем должна справиться настоящая система типов!

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я - ядро участник проекта Ломбок.

...