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

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

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

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

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

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

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

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

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

25 ответов

Поскольку 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.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. Следующая таблица дает обзор:

                                ПАРАМЕТР ПОЛЯ МЕТОДА LOCAL_VARIABLE 
android.support.annotation      X       X       X   
edu.umd.cs.findbugs.annotations X       X       X         X
org.jetbrains.annotation        X       X       X         X
ломбок хххх
javax.validation.constraints XXX

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, поэтому я перечислю их отдельно. У lombok довольно скучный @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.nnotations из 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

Мне очень нравится https://checkerframework.org/, представляющий собой реализацию аннотаций типов ( JSR-308), которая используется для реализации средств проверки дефектов, таких как средство проверки на нулевое значение. Я на самом деле не пробовал других предлагать какое-либо сравнение, но я был доволен этой реализацией.

Я не связан с группой, которая предлагает программное обеспечение, но я фанат.

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

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

  2. Настройка по умолчанию для проверки на нулевое значение работает хорошо: ненулевое значение, кроме локальных (NNEL). По сути, это означает, что по умолчанию средство проверки обрабатывает все (переменные экземпляра, параметры метода, универсальные типы и т. Д.), Кроме локальных переменных, как если бы они имели тип @NonNull по умолчанию. Согласно документации:

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

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

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

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

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

Согласно списку возможностей 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.

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

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

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

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

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

  • Проверка во время выполнения: используйте "if (x == null) ..." (нулевая зависимость) или @javax.validation.NotNull (с проверкой бина) или @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 проигнорируют это (на участниках). Грустно, но правда.
  • Для статической проверки вне IDE существует 2 бесплатных инструмента: Spotbugs(ранее Findbugs) и checkersframework.
  • Библиотека Eclipse имеет @NonNullByDefault, jsr305 имеет только @ParametersAreNonnullByDefault. Это просто удобные обертки, применяющие базовые аннотации ко всему в пакете (или классе), вы можете легко создавать свои собственные. Это может быть использовано на упаковке. Это может конфликтовать с сгенерированным кодом (например, lombok).
  • Eclipse JDT аннотации не применяются к статическим методам возврата и некоторых других случаях
  • Следует избегать использования lombok в качестве экспортируемой зависимости для библиотек, которыми вы делитесь с другими людьми: чем меньше транзитивных зависимостей, тем лучше
  • Использование инфраструктуры проверки Bean является мощным, но требует больших накладных расходов, так что это излишне, просто чтобы избежать ручной проверки нуля.
  • Использование Optional для полей и параметров метода является спорным (об этом легко найти статьи)
  • Нулевые аннотации 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 выдавать предупреждение при разыменовании параметра метода, допускающего значение NULL (на момент написания, версия 3.1 Spotbugs). Может быть, проверочная схема может сделать это.

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

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

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

Вот как применить @Nonnull ко всем классам, методам и полям по умолчанию. См. /questions/10662052/ustanovit-findbugs-notnull-po-umolchaniyu-dlya-vseh-klassov-v-pakete/10662056#10662056 и /questions/22542245/ustarevshie-annotatsii-v-findbugs-20/22542250#22542250

  1. определять @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 https://stackru.com/a/9256595/14731
     */
    @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

JSpecify - это то, что нужно. Фактически: их презентация активно ссылается на этот самый вопрос и указывает, что их цель состоит в том, чтобы наконец получить хороший ответ.

У него есть крупные участники, такие как Android, Guava и Kotlin.

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

org.eclipse.jdt.annotation.NonNull

Смотрите подробности на http://wiki.eclipse.org/JDT_Core/Null_Analysis.

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

более новые проекты shoudl, вероятно, используют jakarta.annotation-api .
Он связан с доступным только для репозиторием javax.annotation,чтения, и вписывается в новую экосистему Джакарты, цель которой - освободить сообщество от всех javax связанные головные боли.

Здесь уже слишком много ответов, но (а) сейчас 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'

Android

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

Чтобы добавить пакет support-annotations, добавьте следующую зависимость в ваш build.gradle:

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

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

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}

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

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

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

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

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

Есть другой способ сделать это в Java 8. Я делаю 2 вещи, чтобы выполнить то, что мне нужно:

  1. Делая обнуляемые поля явными с типами, оборачивая обнуляемые поля java.util.Optional
  2. Проверка того, что все ненулевые поля не равны нулю во время построения с 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 не должен использоваться в аргументах

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

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

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

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

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

  1. поставьте jar api для проверки bean-компонентов и jar с реализацией валидатора аннотаций 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>
    
  2. предоставить MethodValidationPostProcessor для контекста Spring

      @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
    
  3. наконец, вы комментируете свои уроки с 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, Нет необходимости в ручной работе здесь.

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

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

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

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

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

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

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

Установите флажок "Включить нулевой анализ на основе аннотаций"

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

Я использую:

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

Если вы используете Spring 5.x / SpringBoot 2.x, вам обязательно следует использовать аннотации Spring (org.springframework.lang), поскольку они предоставляют вам по умолчанию нулевую проверку пакета с аннотациями. @NonNullFields а также @NonNullApi. У вас даже не будет столкновения с другими NotNull/NonNullаннотации из других зависимостей, которые вы используете. Аннотации должны использоваться в файле package-info.java, который находится в корневом каталоге пакета:

      @NonNullFields
@NonNullApi
package org.company.test;

Чтобы исключить определенные поля, параметры или возвращаемые значения из нулевой проверки, просто явно используйте аннотацию. Вместо использования вы также можете установить @NonNull везде, но, наверное, лучше активировать нулевые проверки с помощью @NonNullFields/@NonNullApi по умолчанию и делать только определенные исключения с.

IDE (Intellij) выделит код, который нарушает нулевые условия. При правильной настройке каждый разработчик может предположить, что поля, параметры и возвращаемые значения не должны быть нулевыми, если только нет @Nullableаннотация. Для получения дополнительной информации ознакомьтесь с этой статьей .

Spring 5 имеет @NonNullApi на уровне пакета. Это кажется удобным выбором для проекта, в котором уже есть зависимости Spring. Все поля, параметры и возвращаемые значения по умолчанию равны @NonNull, а @Nullable можно применять в нескольких местах, которые отличаются.

Файл package-info.java:

@org.springframework.lang.NonNullApi
package com.acme;

https://docs.spring.io/spring-data/commons/docs/current/reference/html/

Разве у Солнца нет своего? Что это:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm

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

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

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

Другие вопросы по тегам