Какую аннотацию @NotNull Java следует использовать?

794

Я хочу сделать свой код более читаемым, а также использовать инструменты, такие как проверка кода IDE и/или анализ статического кода (FindBugs и Sonar), чтобы избежать NullPointerExceptions. Многие из инструментов кажутся несовместимыми с аннотациями @NotNull/@NonNull/@NonNull друг друга, и перечисление всех из них в моем коде было бы ужасно для чтения. Любые предложения, которые являются "лучшими"? Вот список эквивалентных аннотаций, которые я нашел:

  • javax.validation.constraints.NotNull
    Создан для проверки времени выполнения, а не для статического анализа.
    документация

  • edu.umd.cs.findbugs.annotations.NonNull
    Используется Findbugs статический анализ и, следовательно, Sonar (теперь Sonarqube)
    документация

  • javax.annotation.Nonnull
    Это может работать и с Findbugs, но JSR-305 неактивен. (См. Также: Каков статус JSR 305?) source

  • org.jetbrains.annotations.NotNull
    Используется IntelliJ IDEA IDE для статического анализа.
    документация

  • lombok.NonNull
    Используется для управления генерации кода в Project Lombok.
    Аннотации заполнителя, так как нет стандарта.
    источник, документация

  • android.support.annotation.NonNull
    Аннотации маркера доступны в Android, предоставляемые пакетом поддержки-аннотаций
    документация

  • org.eclipse.jdt.annotation.NonNull
    Используется Eclipse для статического анализа кода
    документация

  • 173
    Apache должен изобрести «общую» аннотацию и инструмент, который может преобразовать ее в любую другую аннотацию. Решение проблемы слишком большого числа стандартов состоит в том, чтобы изобрести новый стандарт.
  • 0
    @NotNull внутри идеи также выполняет проверку во время выполнения (по крайней мере, в версии 10.5)
Показать ещё 13 комментариев
Теги:
nullpointerexception
null
ide
annotations

20 ответов

91

Поскольку Oracle решил не стандартизировать @NonNull (и @Nullable) на данный момент, я боюсь, что нет хорошего ответа. Все, что мы можем сделать, это найти прагматическое решение, а мое заключается в следующем:

Синтаксис

С чисто стилистической точки зрения я хотел бы избегать ссылок на IDE, фреймворк или любой инструментарий, кроме самой Java.

Это исключает:

  • android.support.annotation
  • edu.umd.cs.findbugs.annotations
  • org.eclipse.jdt.annotation
  • org.jetbrains.annotations
  • org.checkerframework.checker.nullness.qual
  • lombok.NonNull

Что оставляет нас с javax.validation.constraints или javax.nnation. Первый идет с JEE. Если это лучше, чем javax.nnation, который может прийти в конечном итоге с JSE или вообще никогда, это вопрос дебатов. Я лично предпочитаю javax.annotation, потому что мне не понравится зависимость JEE.

Это оставляет нас

javax.annotation

который также является самым коротким.

Существует только один синтаксис, который будет даже лучше: java.nnotation.Nullable. Поскольку другие пакеты, прошедшие с javax в java в прошлом, javax.annotation будет шагом в правильном направлении.

Реализация

Я надеялся, что все они имеют в основном такую же тривиальную реализацию, но подробный анализ показал, что это не так.

Сначала для сходства:

Аннотации @NonNull имеют строку

public @interface NonNull {}

кроме

  • org.jetbrains.nnotes, который называет его @NotNull и имеет тривиальную реализацию
  • javax.nnation, которая имеет более длительную реализацию
  • javax.validation.constraints, который также называет его @NotNull и имеет реализацию

У @Nullable аннотаций есть строка

public @interface Nullable {}

за исключением (снова) org.jetbrains.nnotes с их тривиальной реализацией.

Для отличий:

Поразительным является то, что

  • javax.annotation
  • javax.validation.constraints
  • org.checkerframework.checker.nullness.qual

все имеют аннотации времени выполнения (@Retention (RUNTIME), в то время как

  • android.support.annotation
  • edu.umd.cs.findbugs.annotations
  • org.eclipse.jdt.annotation
  • org.jetbrains.annotations

являются только временем компиляции (@Retention (CLASS)).

Как описано в этом SO-ответе, влияние аннотаций во время выполнения меньше, чем можно было бы подумать, но они имеют преимущество включения инструментов для выполнения проверок времени выполнения в дополнение к времени компиляции.

Другое важное различие заключается в том, где в коде могут использоваться аннотации. Существует два разных подхода. Некоторые пакеты используют контексты стиля JLS 9.6.4.1. В следующей таблице приведен обзор:


                                FIELD   METHOD  PARAMETER LOCAL_VARIABLE 
android.support.annotation      X       X       X   
edu.umd.cs.findbugs.annotations X       X       X         X
org.jetbrains.annotation        X       X       X         X
lombok                          X       X       X         X
javax.validation.constraints    X       X       X   

org.eclipse.jdt.annotation, javax.annotation и org.checkerframework.checker.nullness.qual использовать контексты, определенные в JLS 4.11, и это, на мой взгляд, правильный способ сделать это.

Это оставляет нас

  • javax.annotation
  • org.checkerframework.checker.nullness.qual

в этом раунде.

Код

Чтобы помочь вам более подробно проанализировать детали, я перечисляю код каждой аннотации ниже. Чтобы упростить сравнение, я удалил комментарии, импорт и аннотацию @Documented. (все они имели @Documented, за исключением классов из пакета Android). Я изменил порядок строк и полей @Target и нормализовал квалификацию.

package android.support.annotation;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER})
public @interface NonNull {}

package edu.umd.cs.findbugs.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface NonNull {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NotNull {String value() default "";}

package javax.annotation;
@TypeQualifier
@Retention(RUNTIME)
public @interface Nonnull {
    When when() default When.ALWAYS;
    static class Checker implements TypeQualifierValidator<Nonnull> {
        public When forConstantValue(Nonnull qualifierqualifierArgument,
                Object value) {
            if (value == null)
                return When.NEVER;
            return When.ALWAYS;
        }
    }
}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf(MonotonicNonNull.class)
@ImplicitFor(
    types = {
        TypeKind.PACKAGE,
        TypeKind.INT,
        TypeKind.BOOLEAN,
        TypeKind.CHAR,
        TypeKind.DOUBLE,
        TypeKind.FLOAT,
        TypeKind.LONG,
        TypeKind.SHORT,
        TypeKind.BYTE
    },
    literals = {LiteralKind.STRING}
)
@DefaultQualifierInHierarchy
@DefaultFor({TypeUseLocation.EXCEPTION_PARAMETER})
@DefaultInUncheckedCodeFor({TypeUseLocation.PARAMETER, TypeUseLocation.LOWER_BOUND})
public @interface NonNull {}

Для полноты: @Nullable реализация:

package android.support.annotation;
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {}

package edu.umd.cs.findbugs.annotations;
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
@Retention(CLASS)
public @interface Nullable {}

package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface Nullable {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface Nullable {String value() default "";}

package javax.annotation;
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RUNTIME)
public @interface Nullable {}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf({})
@ImplicitFor(
    literals = {LiteralKind.NULL},
    typeNames = {java.lang.Void.class}
)
@DefaultInUncheckedCodeFor({TypeUseLocation.RETURN, TypeUseLocation.UPPER_BOUND})
public @interface Nullable {}

Следующие два пакета не имеют @Nullable, поэтому я перечисляю их отдельно. Ломбок имеет довольно скучный @NonNull. В javax.validation.constraints @NonNull фактически является @NotNull и имеет длительную реализацию.

package lombok;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package javax.validation.constraints;
@Retention(RUNTIME)
@Target({ FIELD, METHOD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Constraint(validatedBy = {})
public @interface NotNull {
    String message() default "{javax.validation.constraints.NotNull.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default {};
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        NotNull[] value();
    }
}

Поддержка

Создайте мой опыт javax.annotation, по крайней мере, поддерживается Eclipse и Checker Framework из коробки.

Резюме

Моя идеальная аннотация была бы синтаксисом java.annotation с реализацией Checker Framework.

Если вы не собираетесь использовать Checker Framework, javax.annotation (JSR-305) пока остается вашим лучшим выбором.

Если вы хотите купить в Checker Framework, просто используйте их org.checkerframework.checker.nullness.qual.


источники

  • android.support.annotation от android-5.1.1_r1.jar
  • edu.umd.cs.findbugs.annotations from findbugs-annotations-1.0.0.jar
  • org.eclipse.jdt.annotation от org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
  • org.jetbrains.annotations от jetbrains-annotations-13.0.jar
  • javax.nnation от gwt-dev-2.5.1-sources.jar
  • org.checkerframework.checker.nullness.qual from checker-framework-2.1.9.zip
  • lombok от lombok совершить f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
  • javax.validation.constraints from validation-api-1.0.0.GA-sources.jar
  • 3
    Недостатком javax.annotation является то, что он а) основан на мертвой JSR, б) трудно найти артефакт, который просто предоставляет аннотации и поддерживается. Один из findbugs не является: search.maven.org/…
  • 5
    Еще одно замечание против javax.annotation заключается в том, что это вызывает проблемы с Java 9, потому что другие модули также предоставляют классы в этом пакете (jax-ws).
Показать ещё 5 комментариев
83

Мне очень нравится Checker Framework, которая представляет собой реализацию аннотаций типа (JSR-308), который используется для реализации проверочных проверок, таких как проверка на отсутствие ошибок. Я даже не пробовал других предлагать какое-либо сравнение, но я был доволен этой реализацией.

Я не являюсь аффилированным лицом группы, предлагающей программное обеспечение, но я поклонник.

Четыре вещи, которые мне нравятся в этой системе:

  • У него есть исправления дефектов для nullness (@Nullable), но также есть для неизменяемость и interning (и другие). Я использую первый (nullness), и я пытаюсь использовать второй (неизменяемость/IGJ). Я пробую третий, но я не уверен, что буду использовать его в долгосрочной перспективе. Я еще не уверен в общей полезности других шашек, но приятно знать, что сама структура - это система для реализации множества дополнительных аннотаций и шашек.

  • настройка по умолчанию для проверки нулевой точки работает хорошо: Non-null, кроме локальных (NNEL). В основном это означает, что по умолчанию checker обрабатывает каждый элемент (переменные экземпляра, параметры метода, общие типы и т.д.), За исключением локальных переменных, как если бы они по умолчанию имели тип @NonNull. По документации:

    По умолчанию NNEL приводит к наименьшему количеству явных аннотаций в вашем коде.

    Вы можете установить другое значение по умолчанию для класса или метода, если NNEL не работает для вас.

  • Эта структура позволяет использовать с без создания зависимости от структуры, включив ваши аннотации в комментарии: например /*@Nullable*/. Это хорошо, потому что вы можете комментировать и проверять библиотеку или общий код, но все же можете использовать эту библиотеку/общий код в другом проекте, который не использует фреймворк. Это приятная функция. Я привык использовать его, хотя я склонен теперь включать Checker Framework во все мои проекты.

  • У рамки есть способ аннотировать API-интерфейсы, которые вы используете, которые еще не аннотируются для исключения, используя файлы-заглушки.

  • 3
    Кажется великолепным, и я хотел бы использовать это, но не могу. Почему GPL? Не может ли это быть LGPL вместо этого?
  • 13
    В соответствии с часто задаваемыми вопросами : «Более разрешительная лицензия MIT применяется к коду, который вы, возможно, захотите включить в свою собственную программу, например к аннотациям».
Показать ещё 3 комментария
49

Я использую IntelliJ, потому что я в основном обеспокоен тем, что IntelliJ помещает вещи, которые могут создать NPE. Я согласен с тем, что это разочаровывает отсутствие стандартной аннотации в JDK. Там говорится о добавлении его, он может попасть в Java 7. В этом случае будет еще один выбор!

  • 59
    Обновление: IntelliJ теперь поддерживает все вышеперечисленные аннотации для выделения кода, поэтому вы больше не ограничены аннотациями IntelliJ: blogs.jetbrains.com/idea/2011/03/…
  • 28
    И Eclipse Juno тоже!
Показать ещё 3 комментария
31

В соответствии с список функций Java 7 Аннотации типа JSR-308 отложены на Java 8. Аннотации JSR-305 даже не упоминаются.

Немного информации о состоянии JSR-305 в приложении из последнего проекта JSR-308. Это включает в себя наблюдение, что аннотации JSR-305 кажутся заброшенными. Страница JSR-305 также показывает ее как "неактивную".

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


Фактически, JSR-308 не определяет типы/классы аннотаций, и похоже, что они считают, что это вне сферы действия. (И они правы, учитывая существование JSR-305).

Однако, если JSR-308 действительно выглядит как встраивание в Java 8, это не удивит меня, если бы интерес к JSR-305 возродился. AFAIK, команда JSR-305 официально не отказалась от своей работы. Они только что были спокойны в течение 2+ лет.

Интересно, что Билл Пью (технологическое руководство для JSR-305) является одним из парней за FindBugs.

  • 4
    @pst - текущее расписание выхода Java 8 в общем выпуске в сентябре 2013 года - infoq.com/news/2012/04/jdk-8-milestone-release-dates
  • 2
    Теперь это произошло в марте 2014 года - openjdk.java.net/projects/jdk8 . JSR 308 включен в сборку M7 (см. «104 - Аннотации на типах Java»).
25

Для проектов Android вы должны использовать android.support.annotation.NonNull и android.support.annotation.Nullable. Эти и другие полезные аннотации для Android доступны в Support Library.

Из http://tools.android.com/tech-docs/support-annotations:

Сама библиотека поддержки также была аннотирована этими аннотации, так как пользователь библиотеки поддержки, Android Studio будет уже проверить свой код и выявить потенциальные проблемы на основе этих аннотации.

  • 1
    Было бы полезно представить обоснование этой рекомендации.
  • 2
    tools.android.com/tech-docs/support-annotations "Сама библиотека поддержки также помечена этими аннотациями, так что, как пользователь библиотеки поддержки, Android Studio уже проверит ваш код и отметит потенциальные проблемы на основе этих аннотаций. «.
Показать ещё 1 комментарий
17

Если кто-то просто ищет классы IntelliJ: вы можете получить их из репозитория maven с помощью

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 
  • 0
    Это тот, который заставляет Intellij выдавать предупреждения, да.
  • 0
    Текущая версия (по состоянию на 05/2017) - 15.0
Показать ещё 2 комментария
17

JSR305 и FindBugs являются авторами того же лица. Оба они плохо поддерживаются, но являются такими стандартными, как они есть, и поддерживаются всеми основными IDE. Хорошей новостью является то, что они хорошо работают как есть.

Вот как применить @Nonnull ко всем классам, методам и полям по умолчанию. См. https://stackoverflow.com/questions/13310994/set-findbugs-notnull-as-default-for-all-classes-under-a-package и https://stackoverflow.com/questions/9255738/deprecated-annotations-in-findbugs-2-0

  • Определить @NotNullByDefault
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;


    /**
     * This annotation can be applied to a package, class or method to indicate that the class fields,
     * method return types and parameters in that element are not null by default unless there is: <ul>
     * <li>An explicit nullness annotation <li>The method overrides a method in a superclass (in which
     * case the annotation of the corresponding parameter in the superclass applies) <li> there is a
     * default parameter annotation applied to a more tightly nested element. </ul>
     * <p/>
     * @see /questions/12554/deprecated-annotations-in-findbugs-20/88656#88656
     */
    @Documented
    @Nonnull
    @TypeQualifierDefault(
    {
        ElementType.ANNOTATION_TYPE,
        ElementType.CONSTRUCTOR,
        ElementType.FIELD,
        ElementType.LOCAL_VARIABLE,
        ElementType.METHOD,
        ElementType.PACKAGE,
        ElementType.PARAMETER,
        ElementType.TYPE
    })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NotNullByDefault
    {
    }

2. Добавьте аннотацию к каждому пакету: package-info.java

@NotNullByDefault
package com.example.foo;

ОБНОВЛЕНИЕ. По состоянию на 12 декабря 2012 года JSR 305 указан как "Бездействующий". Согласно документации:

JSR, который был признан "бездействующим" Исполнительным комитетом, или тот, который достиг своей естественной продолжительности жизни.

Похоже, JSR 308 делает его в JDK 8, и хотя JSR не определяет @NotNull, прилагается Checkers Framework. На момент написания этой статьи плагин Maven был недоступен из-за этой ошибки: https://github.com/typetools/checker-framework/issues/183

  • 2
    Исправлена проблема с showtopper для maven. Так что это должен быть вариант снова.
  • 0
    Я использую FindBugs через Maven, моя IDE ничего не делает, это позволяет избежать конкретных аннотаций IDE, что бы вы порекомендовали?
Показать ещё 1 комментарий
12

Eclipse также имеет собственные аннотации.

org.eclipse.jdt.annotation.NonNull

Подробнее см. http://wiki.eclipse.org/JDT_Core/Null_Analysis.

  • 0
    Похоже, что это будет интегрировано из Eclipse 3.8 (Juno), что приведет Eclipse в соответствие с IntelliJ в этом отношении. Также он должен позволять вам настраивать ваши собственные аннотации Null (например, javax.annotation.Nonnull) и иметь возможность иметь значение NotNull по умолчанию.
11

Просто указывая, что API проверки Java (javax.validation.constraints.*) не поставляется с аннотацией @Nullable, что очень полезно в контексте статического анализа. Это имеет смысл для проверки времени выполнения bean, поскольку это значение по умолчанию для любого не примитивного поля в Java (т.е. Ничего не проверять/применять). Для заявленных целей, которые должны весить в сторону альтернатив.

7

Android

Этот ответ специфичен для Android. Android имеет пакет поддержки, называемый support-annotations. Это обеспечивает десятки аннотаций Android, а также предоставляет такие общие, как NonNull, Nullable и т.д.

Чтобы добавить пакет поддержки-аннотаций, добавьте следующую зависимость в свой файл build.gradle:

compile 'com.android.support:support-annotations:23.1.1'

а затем использовать:

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}
7

К сожалению, JSR 308 не добавит больше значений, чем это локальное предложение NNull проекта здесь

Java 8 не будет содержать единую аннотацию по умолчанию или собственную фреймворк Checker. Подобно Find-bugs или JSR 305, этот JSR плохо поддерживается небольшой группой в основном академических команд.

Нет коммерческой силы, поэтому JSR 308 запускает EDR 3 (предыдущий обзор проекта на JCP) СЕЙЧАС, а Java 8 предполагается отправить менее чем за 6 месяцев: -O Аналогично 310 btw. но в отличие от 308 Oracle взял на себя ответственность за то, что теперь от его создателей, чтобы свести к минимуму вред, который он сделает с платформой Java.

Каждый проект, поставщик и академический класс, такие как те, что находятся за Checker Framework и JSR 308, создадут собственную собственную аннотацию проверки.

В течение многих лет исходный код несовместим, пока не будут найдены несколько популярных компромиссов и, возможно, добавлены в Java 9 или 10, или через фреймворки, такие как Apache Commons или Google Guava; -)

5

Различать статический анализ и анализ времени выполнения. Используйте статический анализ для внутренних материалов и анализ времени выполнения для публичных границ вашего кода.

Для вещей, которые не должны быть пустыми:

  • Проверка выполнения: используйте "if (x == null)..." (нулевая зависимость) или @javax.validation.NotNull (с проверкой bean-компонента) или @lombok.NonNull (простой и простой) или guavas Preconditions.checkNotNull(...)

    • Используйте опцию для типов возвращаемых методов (только). Либо Java8, либо Guava.
  • Статическая проверка: используйте аннотацию @NonNull

  • Где он подходит, используйте аннотации @... NonnullByDefault на уровне класса или пакета. Создавайте эти аннотации самостоятельно (примеры легко найти).
    • Else, используйте @... CheckForNull по методу возвращается, чтобы избежать NPE

Это должно дать лучший результат: предупреждения в среде IDE, ошибки с помощью Findbugs и checkerframework, значимые исключения во время выполнения.

Не ожидайте, что статические проверки будут зрелыми, их именование не стандартизировано, а разные библиотеки и IDE обрабатывают их по-другому, игнорируя их. Классы JAR305 javax.annotations. * Выглядят как стандартные, но их нет, и они вызывают разделенные пакеты с помощью Java9+.

Некоторые пояснения:

  • Findbugs/spotbugs/jsr305 с пакетом javax.validation. * Столкновение с другими модулями в Java9+, также возможно нарушение лицензии Oracle
  • Аннотации Spotbugs по-прежнему зависят от аннотаций jsr305/findbugs в compiletime (на момент написания https://github.com/spotbugs/spotbugs/issues/421)
  • jetbrains @NotNull name конфликтует с @javax.validation.NotNull.
  • фреймбраны, затмение или чек-метры для статической проверки имеют преимущество перед javax.nnotes, что они не сталкиваются с другими модулями в Java9 и выше
  • @javax.annotations.Nullable не означает Findbugs/Spotbugs, что вы (или ваша IDE) думаете, что это означает. Findbugs игнорируют его (для участников). Ужасно, но верно (https://sourceforge.net/p/findbugs/bugs/1181)
  • Для статической проверки вне IDE существуют 2 бесплатных инструмента: Spotbugs (ранее Findbugs) и checkersframework.
  • Библиотека Eclipse имеет @NonNullByDefault, jsr305 имеет только @ParametersAreNonnullByDefault. Это всего лишь удобные обертки, применяющие базовые аннотации ко всему в пакете (или классе), вы можете легко создать свой собственный. Это можно использовать на упаковке. Это может противоречить сгенерированному коду (например, ломбок).
  • Аннотации Eclipse jdt не применимы к возврату статических методов и некоторым другим случаям
  • Использовать ломбок в качестве экспортируемой зависимости следует избегать для библиотек, которые вы разделяете с другими людьми, менее транзитивных зависимостей, тем лучше
  • Использование системы проверки подлинности Bean является мощным, но требует больших накладных расходов, так что излишнее, чтобы избежать ручной проверки на нуль.
  • Использование Опция для полей и параметров метода противоречива (вы можете легко найти статьи)
  • Андроидные аннотации Android являются частью библиотеки поддержки Android, они поставляются со множеством других классов и не играют хорошо с другими аннотациями/инструментами

Перед Java9 это моя рекомендация:

// file: package-info.java
@javax.annotation.ParametersAreNonnullByDefault
package example;


// file: PublicApi
package example;

public class PublicApi {

    /**
     * @param firstname MUST NOT be null
     * @param lastname MUST NOT be null
     */
    public Person createPerson(
            // Spotbugs ignores the param annotations, but IDEs will show problems
            @Nullable String firstname, // Users  might send null
            @Nullable String lastname // Users might send null
            ) {
        if (firstname == null) throw new IllagalArgumentException(...);
        if (lastname == null) throw new IllagalArgumentException(...);
        return doCreatePerson(fistname, lastname, nickname);
    }

    @NonNull // Spotbugs checks that method cannot return null
    private Person doCreatePerson(
             String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefault
             String lastname,
             @Nullable String nickname // tell Spotbugs null is ok
             ) {
         return new Person(firstname, lastname, nickname);
    }

    @CheckForNull // Do not use @Nullable here, Spotbugs will ignore it, though IDEs respect it
    private Person getNickname(
         String firstname,
         String lastname) {
         return NICKNAMES.get(firstname + ':' + lastname);
    }
}

Обратите внимание, что нет способа заставить Spotbugs вызывать предупреждение, когда параметр nullable метода разыменовывается (на момент написания, версия 3.1 Spotbugs). Может быть, checkerframework может это сделать.

5

Ожидая, что это будет отсортировано вверх по течению (Java 8?), вы также можете просто определить свои собственные проектно-локальные аннотации @NotNull и @Nullable. Это может быть полезно и в случае, если вы работаете с Java SE, где javax.validation.constraints недоступно по умолчанию.

import java.lang.annotation.*;

/**
 * Designates that a field, return value, argument, or variable is
 * guaranteed to be non-null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface NotNull {}

/**
 * Designates that a field, return value, argument, or variable may be null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface Nullable {}

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

4

Если вы разрабатываете для android, вы несколько привязаны к Eclipse (редактируйте: в момент написания, не больше), у которого есть свои собственные аннотации. Он включен в Eclipse 3.8+ (Juno), но по умолчанию отключен.

Вы можете включить его в настройках > Java > Компилятоp > Ошибки/Предупреждения > Нулевой анализ (сворачивающийся раздел внизу).

Отметьте "Включить нулевой анализ на основе аннотаций"

http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage содержит рекомендации по настройкам. Однако, если у вас есть внешние проекты в вашей рабочей области (например, в facebook SDK), они могут не удовлетворять этим рекомендациям, и вы, вероятно, не хотите исправлять их при каждом обновлении SDK; -)

Я использую:

  • Доступ к нулевому указателю: ошибка
  • Нарушение нулевой спецификации: Ошибка (связанная с точкой # 1)
  • Потенциальный доступ к нулевым указателям: предупреждение (в противном случае у SDK в facebook были бы предупреждения)
  • Конфликт между нулевыми аннотациями и нулевым выводом: Предупреждение (связанное с точкой # 3)
  • 3
    привязан к Затмению? Не правда.
  • 1
    @DavidCowden IntelliJ IDEA с поддержкой Android-разработки, я думаю, была доступна за некоторое время до того, как AndroidStudio был взломан.
Показать ещё 4 комментария
3

Если вы работаете над большим проектом, возможно, вам лучше создать свои собственные @Nullable и/или @NotNull аннотации.

Например:

@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
@java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD,
                              java.lang.annotation.ElementType.METHOD,    
                              java.lang.annotation.ElementType.PARAMETER,
                              java.lang.annotation.ElementType.LOCAL_VARIABLE})
public @interface Nullable 
{
}

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

Несмотря на то, что это не является строгой наукой, я считаю, что имеет смысл использовать для этого внутренний класс.

  • Это внутренняя вещь. (отсутствие функционального или технического воздействия).
  • Со многими многими обычаями.
  • IDE, например, IntelliJ поддерживает пользовательские аннотации @Nullable/@NotNull.
  • Большинство фреймворков предпочитают также использовать свою собственную внутреннюю версию.

Дополнительные вопросы (см. комментарии):

Как настроить это в IntelliJ?

Нажмите "полицейский" в нижнем правом углу строки состояния IntelliJ. И нажмите "Настроить проверки" во всплывающем окне. Следующий... Изображение 1381

  • 1
    Я попробовал ваш совет, но idea ничего не говорит о void test(@NonNull String s) {} вызываемом test(null);
  • 3
    @ user1244932 Вы имеете в виду IntelliJ IDEA? Вы можете настроить аннотации обнуляемости, которые он использует для статического анализа. Я точно не знаю, где, но одно место для их определения - «Файл> Настройки> Сборка, Выполнение, Развертывание> Компилятор», и там есть кнопка «Настроить аннотации ...».
Показать ещё 1 комментарий
3

В Java 8 есть еще один способ. Я делаю 2 вещи для достижения того, что мне нужно:

  • Создание полей с нулевыми значениями с явными типами путем обнуления полей с нулевым значением с помощью java.util.Optional
  • Проверка того, что все поля, не имеющие значения NULL, не равны нулю при времени построения с помощью java.util.Objects.requireNonNull

Пример:

import static java.util.Objects.requireNonNull;

public class Role {

  private final UUID guid;
  private final String domain;
  private final String name;
  private final Optional<String> description;

  public Role(UUID guid, String domain, String name, Optional<String> description) {
    this.guid = requireNonNull(guid);
    this.domain = requireNonNull(domain);
    this.name = requireNonNull(name);
    this.description = requireNonNull(description);
  }

Итак, мой вопрос: нам даже нужно комментировать при использовании java 8?

Изменить: позже я выяснил, что некоторые считают неправильную практику использовать Optional в аргументах, есть хорошее обсуждение с плюсами и минусами здесь Почему Java 8 необязательно не будет используется в аргументах

  • 0
    Я бы сказал, что вам по-прежнему нужна аннотация @NotNull для всех 4-х формальных параметров, чтобы контролеры статического анализа знали, что ни один из них не должен быть нулевым. В языке Java пока нет ничего, что могло бы обеспечить это. Вы также должны проверить, что описание не является нулевым, если вы программируете в обороне.
  • 0
    @jazin, так как невозможно создать экземпляр, в котором guid == null || домен == ноль || name == null Какое значение имеет наличие инструмента статического анализа для выполнения этих проверок? Спасибо за указание на проблему с описанием выше, я отредактировал и исправил: this.description = checkNotNull(description);
Показать ещё 9 комментариев
2

Если вы создаете свое приложение с помощью Spring Framework, я бы предложил использовать javax.validation.constraints.NotNull исходя из Beans Проверка в следующей зависимости:

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>

Основное преимущество этой аннотации состоит в том, что Spring обеспечивает поддержку как параметров метода, так и полей классов, аннотированных с помощью javax.validation.constraints.NotNull. Все, что вам нужно сделать, чтобы включить поддержку:

  • поставляем api jar для проверки и jar для beans с реализацией валидатора jsr-303/jsr-349 аннотаций (который связан с зависимостью Hibernate Validator 5.x):

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.4.1.Final</version>
    </dependency>
    
  • предоставлять метод ValueValidationPostProcessor в Spring контекст

      @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
    
  • наконец, вы аннотируете свои классы с помощью Spring org.springframework.validation.annotation.Validated, и проверка будет автоматически обрабатываться Spring.

Пример:

@Service
@Validated
public class MyServiceImpl implements MyService {

  @Override
  public Something doSomething(@NotNull String myParameter) {
        // No need to do something like assert myParameter != null  
  }
}

Когда вы пытаетесь вызвать метод doSomething и передаете значение null в качестве значения параметра, Spring (с помощью HibernateValidator) выкинет ConstraintViolationException. Нет необходимости в manuall здесь.

Вы также можете проверить возвращаемые значения.

Еще одно важное преимущество javax.validation.constraints.NotNull для beans Framework Validation заключается в том, что на данный момент он все еще разработан и новые возможности запланированы для новой версии 2.0.

Как насчет @Nullable? В beans Validation 1.1 нет ничего подобного. Ну, я мог бы утверждать, что если вы решите использовать @NotNull, чем все, что НЕ комментируется с помощью @NonNull, эффективно "обнуляется", поэтому аннотация @Nullable бесполезна.

2

Солнце не имеет собственного теперь? Что это:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm

Кажется, что он упакован со всеми версиями Java, которые я использовал в течение последних нескольких лет.

Изменить: Как уже упоминалось в комментариях ниже, вы, вероятно, не захотите их использовать. В этом случае мой голос за аннотации IntelliJ jetbrains!

  • 10
    Я понятия не имею, что это такое, но имя пакета должно быть БОЛЬШОЙ КЛЮЧОМ, которое НЕ предназначено для общего использования.
  • 3
    Обычно воздерживаются от использования классов в пространстве имен com.sun, поскольку они являются внутренними; не предназначен для непосредственного использования; и без каких-либо гарантий относительно их доступности или поведения в будущем. Нужно иметь действительно солидный случай, чтобы напрямую использовать артефакт com.sun.
Показать ещё 2 комментария
1

Одна из приятных вещей о IntelliJ заключается в том, что вам не нужно использовать свои аннотации. Вы можете написать свой собственный, или вы можете использовать все, что вам нравится. Вы даже не ограничены одним типом. Если вы используете две библиотеки, которые используют разные аннотации @NotNull, вы можете указать IntelliJ использовать их оба. Для этого перейдите в "Настроить инспекции", нажмите "Проверка условий и исключений" и нажмите кнопку "Настроить проверки". Я использую Nullness Checker везде, где могу, поэтому я настроил IntelliJ для использования этих аннотаций, но вы можете заставить его работать с любым другим инструментом, который вы хотите. (У меня нет мнения о других инструментах, потому что я много лет использую инспекции IntelliJ, и я их люблю.)

1

Другой вариант - аннотации, предоставленные ANTLR 4. Следуя Pull Request # 434, артефакт, содержащий аннотации @NotNull и @Nullable включает обработчик аннотации, который производит ошибки времени компиляции и/или предупреждения в случае неправильного использования одного из этих атрибутов (например, если оба применяются к одному элементу или если @Nullable применяется к элементу с примитивным типом), Обработчик аннотации обеспечивает дополнительную уверенность в процессе разработки программного обеспечения, что информация, передаваемая при применении этих аннотаций, является точной, в том числе в случае наследования метода.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню