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

Я хочу сделать свой код более читаемым, а также использовать инструменты, такие как проверка кода 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 для статического анализа кода
    документация

Ответ 1

Поскольку JSR 305 (целью которого было стандартизировать @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.annotation. Бывший поставляется с JEE. Если это лучше, чем javax.annotation, который может в конечном итоге прийти с JSE или никогда вообще, является предметом споров. Я лично предпочитаю javax.annotation, потому что мне не нравится зависимость от JEE.

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

javax.annotation

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

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

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

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

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

public @interface NonNull {}

кроме

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

Все аннотации @Nullable имеют строку

public @interface Nullable {}

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

Для различий:

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

  • 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 из 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.annotation из gwt-dev-2.5.1-sources.jar
  • org.checkerframework.checker.nullness.qual из checker-framework-2.1.9.zip
  • lombok из lombok commit f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
  • javax.validation.constraints из validation-api-1.0.0.GA-sources.jar

Ответ 2

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

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

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

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

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

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

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

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

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

Ответ 3

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

Ответ 4

В соответствии с список функций 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.

Ответ 5

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

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

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

Ответ 6

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

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 

Ответ 7

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

Вот как применить @Nonnull ко всем классам, методам и полям по умолчанию. См. fooobar.com/questions/12553/... и fooobar.com/questions/12554/...

  • Определить @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

Ответ 9

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

Ответ 10

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

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

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

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

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

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

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

Некоторые примечания к объяснениям:

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

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

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


// file: PublicApi
package example;

public interface PublicApi {

    Person createPerson(
        // NonNull by default due to package-info.java above
        String firstname,
        String lastname);
}

// file: PublicApiImpl
public class PublicApiImpl implements PublicApi {
    public Person createPerson(
            // In Impl, handle cases where library users still pass null
            @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 выдавать предупреждение при разыменовании параметра метода, допускающего обнуляемость (на момент написания, версия 3.1 Spotbugs). Может быть, это можно сделать с помощью контрольной рамки.

К сожалению, эти аннотации не делают различий между случаями открытого метода библиотеки с произвольными местами вызова и непубличными методами, в которых может быть известен каждый из них. Поэтому двойное значение: "Укажите, что null нежелателен, но, тем не менее, подготовьтесь к тому, что null будет передан", невозможно в одном объявлении, поэтому приведенный выше пример имеет разные аннотации для интерфейса и реализации.

В случаях, когда подход с разделенным интерфейсом нецелесообразен, следующий подход является компромиссом:

        public Person createPerson(
                @NonNull String firstname,
                @NonNull String lastname
                ) {
            // even though parameters annotated as NonNull, library clients might call with null.
            if (firstname == null) throw new IllagalArgumentException(...);
            if (lastname == null) throw new IllagalArgumentException(...);
            return doCreatePerson(fistname, lastname, nickname);
        }

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

Ответ 11

К сожалению, 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; -)

Ответ 12

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) {}

Ответ 13

Ожидая, что это будет отсортировано вверх по течению (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 {}

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

Ответ 14

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

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

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

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

Я использую:

  • Доступ к нулевому указателю: ошибка
  • Нарушение нулевой спецификации: Ошибка (связанная с точкой # 1)
  • Потенциальный доступ к нулевым указателям: предупреждение (в противном случае у SDK в facebook были бы предупреждения)
  • Конфликт между нулевыми аннотациями и нулевым выводом: Предупреждение (связанное с точкой # 3)

Ответ 15

Если вы работаете над большим проектом, возможно, вам лучше создать свои собственные @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. И нажмите "Настроить проверки" во всплывающем окне. Следующий... настроить аннотации

Ответ 16

В 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 необязательно не будет используется в аргументах

Ответ 17

Здесь уже слишком много ответов, но (а) это 2019 год, и до сих пор нет "стандартного" Nullable и (б) нет других ответов, ссылающихся на Kotlin.

Ссылка на Kotlin важна, потому что Kotlin на 100% совместим с Java и имеет основную функцию нулевой безопасности. При вызове библиотек Java можно воспользоваться этими аннотациями, чтобы сообщить инструментам Kotlin, может ли API-интерфейс Java принимать или возвращать null.

Насколько я знаю, единственными пакетами Nullable совместимыми с Kotlin, являются org.jetbrains.annotations и android.support.annotation (теперь androidx.annotation). Последний совместим только с Android, поэтому его нельзя использовать в проектах JVM/Java/Kotlin, отличных от Android. Тем не менее, пакет JetBrains работает везде.

Поэтому, если вы разрабатываете пакеты Java, которые также должны работать в Android и Kotlin (и поддерживаться Android Studio и IntelliJ), ваш лучший выбор, вероятно, - пакет JetBrains.

Maven:

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations-java5</artifactId>
    <version>15.0</version>
</dependency>

Gradle:

implementation 'org.jetbrains:annotations-java5:15.0'

Ответ 18

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

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

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

Ответ 19

Если вы создаете свое приложение с помощью 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 бесполезна.

Ответ 20

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

Ответ 21

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