我希望使我的代码更具可读性,以及使用工具,如IDE代码检查和/或静态代码分析(FindBugs和Sonar),以避免nullpointerexception。许多工具似乎与彼此的@NotNull/@NonNull/ @NonNull注释不兼容,在我的代码中列出所有这些工具会让人难以阅读。有没有什么建议,哪一个是“最好的”?下面是我找到的等价注释列表:

javax.validation.constraints.NotNull Created for runtime validation, not static analysis. documentation edu.umd.cs.findbugs.annotations.NonNull Used by FindBugs (dead project) and its successor SpotBugs static analysis and therefore Sonar (now Sonarqube) FindBugs documentation, SpotBugs documentation javax.annotation.Nonnull This might work with FindBugs too, but JSR-305 is inactive. (See also: What is the status of JSR 305?) source org.jetbrains.annotations.NotNull Used by IntelliJ IDEA IDE for static analysis. documentation lombok.NonNull Used to control code generation in Project Lombok. Placeholder annotation since there is no standard. source, documentation androidx.annotation.NonNull Marker annotation available in Android, provided by annotation package documentation org.eclipse.jdt.annotation.NonNull Used by Eclipse for static code analysis documentation


当前回答

Another option is the annotations provided with ANTLR 4. Following Pull Request #434, the artifact containing the @NotNull and @Nullable annotations includes an annotation processor that produces compile-time errors and/or warnings in the event one of these attributes is misused (for example, if both are applied to the same item, or if @Nullable is applied to item with a primitive type). The annotation processor provides additional assurance during the software development process that the information conveyed by the application of these annotations is accurate, including in cases of method inheritance.

其他回答

如果你在做一个大项目,你最好创建自己的@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 
{
}

如果您使用了正确的保留策略,那么注释在运行时将不可用。从这个角度来看,它只是一种内在的东西。

尽管这不是一门严格的科学,但我认为使用内部类是最有意义的。

这是一个内在的东西。(没有功能或技术影响) 有很多很多的用法。 像IntelliJ这样的IDE支持自定义的@Nullable/@NotNull注释。 大多数框架也喜欢使用自己的内部版本。

其他问题(见评论):

如何在IntelliJ中配置这个?

点击IntelliJ状态栏右下角的“警官”。在弹出窗口中单击“配置巡检”。下一个……

我使用IntelliJ,因为我最关心的是IntelliJ标记可能产生NPE的东西。我同意在JDK中没有标准注释是令人沮丧的。有传言说要添加它,它可能会加入到Java 7中。这样的话,就多了一个选择!

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/#repositories.nullability.annotations

如果你正在使用Spring框架构建应用程序,我建议使用来自bean Validation的javax.validation.constraints.NotNull,它被打包在以下依赖项中:

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

这种注释的主要优点是Spring同时支持用javax.validation.constraints.NotNull注释的方法参数和类字段。要启用支持,您需要做的是:

supply the api jar for beans validation and jar with implementation of validator of jsr-303/jsr-349 annotations (which comes with Hibernate Validator 5.x dependency): <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> provide MethodValidationPostProcessor to spring's context @Configuration @ValidationConfig public class ValidationConfig implements MyService { @Bean public MethodValidationPostProcessor providePostProcessor() { return new MethodValidationPostProcessor() } } finally you annotate your classes with Spring's org.springframework.validation.annotation.Validated and validation will be automatically handled by 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对Beans验证框架的另一个重要好处是,目前它仍在开发中,新特性计划在新版本2.0中实现。

@Nullable呢?在Beans Validation 1.1中没有类似的东西。好吧,我可以争辩说,如果你决定使用@ nonull,而不是任何没有用@NonNull注释的东西都是有效的“nullable”,所以@Nullable注释是无用的。

由于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。null

这使得我们只能使用javax.validation.constraints或javax.annotation。 前者随JEE一起提供。如果这比javax更好。注释可能最终随JSE一起出现,也可能永远不会出现,这是一个有争议的问题。 我个人更喜欢javax。注释,因为我不喜欢JEE依赖。

这就留给我们

javax.annotation

这也是最短的一个。

只有一种语法会更好:java.annotation.Nullable。随着其他课程的毕业 从javax到Java,过去的javax。注释会 向正确的方向迈出一步。

实现

我希望它们都有基本相同的琐碎实现, 但一项详细的分析表明,事实并非如此。

首先是相似之处:

@NonNull注释都有一行

public @interface NonNull {}

除了

它将其命名为@NotNull,并有一个简单的实现 javax。具有较长实现的注释 也叫@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回答了运行时注释的影响 比人们想象的要小,但他们有好处吗 使工具能够执行运行时检查的 编译时1。

另一个重要的区别是代码中注释的使用位置。 有两种不同的方法。一些包使用JLS 9.6.4.1样式上下文。下表给出了概述:

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

org.eclipse.jdt。注释、javax。Annotation和org.checkerframework.checker. nullnness .qual使用中定义的上下文 JLS 4.11,在我看来这是正确的方法。

这就留给我们

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

在这一轮。

Code

为了帮助您自己进一步比较细节,我在下面列出了每个注释的代码。 为了便于比较,我删除了注释、导入和@Documented注释。 (除了Android包中的类,它们都有@Documented)。 我对行和@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。注释至少被Eclipse和Checker框架开箱即用所支持。

总结

我的理想注释是java。注释语法与检查器框架实现。

如果你不打算使用检查器框架,javax。注释(JSR-305)仍然是目前最好的选择。

如果您愿意购买检查器框架,请使用 org.checkerframework.checker.nullness.qual。


来源

android.support.annotation from android-5.1.1_r1.jar edu.umd.cs.findbugs.annotations from findbugs-annotations-1.0.0.jar org.eclipse.jdt.annotation from org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar org.jetbrains.annotations from jetbrains-annotations-13.0.jar javax.annotation from gwt-dev-2.5.1-sources.jar org.checkerframework.checker.nullness.qual from checker-framework-2.1.9.zip lombok from lombok commit f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4 javax.validation.constraints from validation-api-1.0.0.GA-sources.jar