Перевірте параметри, помічені за допомогою @Nonnull, на null?


19

Ми почали використовувати FindBugs і анотувати свої параметри @Nonnullналежним чином, і це чудово підходить для виявлення помилок на початку циклу. Поки ми продовжували перевірку цих аргументів щодо nullвикористання Guava checkNotNull, але я вважаю за краще перевіряти nullлише ті краї - місця, де значення може входити без перевірки null, наприклад, запит SOAP.

// service layer accessible from outside
public Person createPerson(@CheckForNull String name) {
    return new Person(Preconditions.checkNotNull(name));
}

...

// internal constructor accessed only by the service layer
public Person(@Nonnull String name) {
    this.name = Preconditions.checkNotNull(name);  // remove this check?
}

Я розумію, що @Nonnullне блокує nullзначення себе.

Однак, враховуючи, що FindBugs вкаже де завгодно, що значення переноситься з немаркованого поля на одне позначене @Nonnull, чи не можемо ми залежати від нього, щоб зафіксувати ці випадки (що це робить), не перевіряючи ці значення для того, nullде вони будуть передані система? Я наївний, щоб хотіти довіряти інструменту та уникати цих детальних перевірок?

Підсумок: Хоча другий nullчек нижче видається безпечним , чи це погана практика?

Це питання, мабуть, занадто схоже на Чи слід перевіряти на нуль, якщо він не очікує нуля , але я запитую конкретно стосовно @Nonnullанотації.

Відповіді:


6

Якщо ви не довіряєте FindBug, можливо, це може використовувати твердження. Таким чином ви уникаєте проблем, згаданих користувачем MSalters, але все-таки маєте перевірку. Звичайно, такий підхід може бути непридатним, якщо такий невдалий підхід недоцільний, тобто вам доведеться спіймати будь-які винятки.

І далі відповісти на питання, чи це погана практика. Ну, це сперечається, але я б не вважав цього. Я розглядаю цю примітку FindBug як легку специфікацію, що відповідає дизайну за принципом контракту.

При проектуванні за контрактом ви встановлюєте договір між методом та його абонентом. Договір складається з передумов, які абонент погоджується виконати під час виклику методу, і передумови, які, у свою чергу, виконуються методом після виконання, якщо його попередня умова виконана.

Однією з переваг цього методу розробки є те, що ви можете уникнути так званого стилю оборонного програмування (у якому ви чітко перевіряєте всі недійсні значення параметрів тощо). Натомість ви можете покластися на контракт і уникати зайвих перевірок для підвищення продуктивності та читальності.

Контракти можуть бути використані для перевірки твердження під час виконання, який дотримується вищезазначеного принципу відмов, у якому ви хочете, щоб ваша програма вийшла з ладу при порушенні контракту, даючи вам підказку для визначення джерела помилки. (Невдала попередня умова означає, що абонент зробив щось не так; невдала постумова вказує на помилку впровадження даного методу)

Крім того, контракти можуть бути використані для статичного аналізу, який намагається зробити висновки про вихідний код, фактично не виконуючи його.

Анотація @nonnull може розглядатися як передумова, що використовується для статичного аналізу інструментом FindBugs. Якщо ви віддаєте перевагу такому підходу, як перевірка твердження під час виконання, тобто перша стратегія відмови, слід розглянути можливість використання тверджень твердження як вбудованої Java. Або, можливо, адаптуватися до більш досконалої стратегії специфікації, використовуючи мову специфікації поведінкового інтерфейсу, таку як мова моделювання Java (JML).

JML - це розширення Java, в якому специфікація вбудована в спеціальні Java Comments. Перевагою цього підходу є те, що ви можете використовувати складні специфікації, навіть використовуючи підхід до розробки, в якому ви покладаєтесь лише на специфікації, а не на деталі реалізації та використовуєте різні інструменти, що використовують специфікацію, наприклад, згадані інструменти перевірки часу виконання, автоматизована генерація одиничних тестів або документації.

Якщо ви поділяєте мою точку зору на те, що @nonnull є (легким) контрактом, було б звичайною практикою не додавати додаткові перевірки, оскільки первісна ідея цього принципу - уникати оборонного програмування.


2
Саме так я використовую @Nonnull: як специфікацію контракту. Я знімав оборонні чеки за контрактом і до цих пір не мав проблем.
Девід Харкнесс

4

Ну, подумайте, чому ви не пишете

this.name = Preconditions.checkNotNull(name);  // Might be necessary
that.name = Preconditions.checkNotNull(this.name);  // Who knows?

Програмування - це не чорна магія. Змінні не раптом стають нульовими. Якщо ви знаєте, що змінна не є Null, і ви знаєте, що вона не змінена, тоді не перевіряйте її.

Якщо ви все-таки це перевірите, якийсь програміст у майбутньому (можливо, ви) витратить багато часу, щоб з'ясувати, чому така перевірка існує. Зрештою, чек повинен бути там, зрештою, так що ви не помічаєте?


3
У @Nonnullконтракті обумовлює , що абоненти не повинні передати nullв конструктор, і FindBugs використовує статичний аналіз для виявлення викликів , які могли б дозволити null--specifically викликів , які проходять значення не помічені @Nonnullсебе. Але той, хто телефонує, може передати nullта проігнорувати попередження від FindBugs.
Девід Харкнесс

Програмування в ідеалі не є чорною магією. На жаль, застережень та сюрпризів багато, особливо під час роботи з деяким кодом одночасності ♬ ~ ᕕ (ᐛ) ᕗ
Тім Харпер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.