ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

我应该使用哪个@NotNull Java注释?

2019-09-11 03:01:25  阅读:402  来源: 互联网

标签:java null nullpointerexception annotations ide


我希望使我的代码更具可读性,并使用IDE代码检查和/或静态代码分析(FindBugs和Sonar)等工具来避免NullPointerExceptions.许多工具似乎与彼此不兼容的@NotNull / @NonNull / @Nonnull注释并列出我的代码中的所有这些工具都很难阅读.有什么建议是“最好的”吗?这是我发现的等效注释列表:

> javax.validation.constraints.NotNull
创建用于运行时验证,而不是静态分析.
documentation
> edu.umd.cs.findbugs.annotations.NonNull
Findbugs静态分析使用,因此声纳(现在Sonarqube)
documentation
> javax.annotation.Nonnull
这可能也适用于Findbugs,但JSR-305处于非活动状态. (另见:What is the status of JSR 305?)
source
> org.jetbrains.annotations.NotNull
由IntelliJ IDEA IDE用于静态分析.
documentation
> lombok.NonNull
用于控制Project Lombok中的代码生成.
占位符注释,因为没有标准.
source,
documentation
> android.support.annotation.NonNull
Android中提供的标记注释,由support-annotations包提供
documentation
> org.eclipse.jdt.annotation.NonNull
由Eclipse用于静态代码分析
documentation

解决方法:

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)).

this SO answer所述,运行时注释的影响
比人们想象的要小,但它们有好处
启用运行时检查的工具除了
编译时间.

另一个重要的区别是在代码中可以使用注释.
有两种不同的方法.某些包使用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,所以我单独列出它们
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的支持.

摘要

我理想的注释是带有Checker Framework实现的java.annotation语法.

如果您不打算使用Checker Framework,那么javax.annotation(JSR-305)仍然是您最好的选择.

如果您愿意购买Checker Framework,请使用
他们的org.checkerframework.checker.nullness.qual.

来源

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

标签:java,null,nullpointerexception,annotations,ide
来源: https://codeday.me/bug/20190911/1803449.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有