我希望使我的代码更具可读性,以及使用工具,如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


当前回答

不幸的是,JSR 308将不会添加比这个项目本地非空建议更多的值

Java 8将不会提供单一的默认注释或自己的Checker框架。 类似于Find-bugs或JSR 305,这个JSR由一小群主要是学术团队维护得很差。

它背后没有商业力量,因此JSR 308现在发布EDR 3 (JCP的早期草案审查),而Java 8应该在不到6个月内发布:-O 顺便说一句,类似于310。但与308不同的是,Oracle现在已经从其创始人手中接管了这一业务,以最大限度地减少它对Java平台的伤害。

每个项目、供应商和学术类,比如检查器框架和JSR 308背后的那些,都将创建自己的专有检查器注释。

让源代码在未来几年不兼容,直到找到一些流行的妥协,并可能添加到Java 9或10中,或者通过Apache Commons或谷歌Guava这样的框架;-)

其他回答

这里已经有太多答案了,但是(a)现在是2019年,仍然没有“标准”Nullable, (b)没有其他答案引用Kotlin。

引用Kotlin是很重要的,因为Kotlin与Java是100%可互操作的,并且它有一个核心的Null安全特性。在调用Java库时,它可以利用这些注释让Kotlin工具知道Java API是否可以接受或返回null。

据我所知,唯一与Kotlin兼容的Nullable包是org.jetbrains.annotations和android.support.annotation(现在是androidx.annotation)。后者只与Android兼容,所以不能在非Android的JVM/Java/Kotlin项目中使用。然而,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'

JSpecify将是一种方法(当它准备好时)。事实上,他们的陈述积极地与这个问题联系在一起,并明确表示他们的目标是最终得到一个好的答案。

它拥有Android、Guava和Kotlin等主要参与者。

我非常喜欢检查器框架,它是类型注释(JSR-308)的实现,用于实现像null检查器这样的缺陷检查器。我并没有尝试其他任何方法进行比较,但我对这个实现感到满意。

我没有加入提供该软件的组织,但我是它的粉丝。

我喜欢这个系统的四个方面:

It has a defect checkers for nullness (@Nullable), but also has ones for immutability and interning (and others). I use the first one (nullness) and I'm trying to get into using the second one (immutability/IGJ). I'm trying out the third one, but I'm not certain about using it long term yet. I'm not convinced of the general usefulness of the other checkers yet, but its nice to know that the framework itself is a system for implementing a variety of additional annotations and checkers. The default setting for nullness checking works well: Non-null except locals (NNEL). Basically this means that by default the checker treats everyhing (instance variables, method parameters, generic types, etc) except local variables as if they have a @NonNull type by default. Per the documentation: The NNEL default leads to the smallest number of explicit annotations in your code. You can set a different default for a class or for a method if NNEL doesn't work for you. This framework allows you to use with without creating a dependency on the framework by enclosing your annotations in a comment: e.g. /*@Nullable*/. This is nice because you can annotate and check a library or shared code, but still be able to use that library/shared coded in another project that doesn't use the framework. This is a nice feature. I've grown accustom to using it, even though I tend to enable the Checker Framework on all my projects now. The framework has a way to annotate APIs you use that aren't already annotated for nullness by using stub files.

在Java 8中还有另一种方法可以做到这一点。 我正在做两件事来完成我所需要的:

通过使用java.util.Optional包装可空字段,使可空字段显式地使用类型 在构造时使用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的Optional不应该在参数中使用

考虑到在参数中使用Optional不是最佳实践,我们需要2个构造函数:

public class Role {
      
      // Required fields, will not be null (unless using reflection) 
      private final UUID guid;
      private final String domain;
      private final String name;
      // Optional field, not null but can be empty
      private final Optional<String> description;

  //Non null description
  public Role(UUID guid, String domain, String name, String description) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);

        // description will never be null
        requireNonNull(description);

        // but wrapped with an Optional
        this.description = Optional.of(description);
      }

  // Null description is assigned to Optional.empty
  public Role(UUID guid, String domain, String name) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);
        this.description = Optional.empty();
      }
  //Note that this accessor is not a getter.
  //I decided not to use the "get" suffix to distinguish from "normal" getters 
  public Optional<String> description(){ return description;} 
 }

太阳现在没有自己的了吗?这是什么: http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm

这似乎与我在过去几年中使用过的所有Java版本都打包在一起。

编辑:正如下面评论中提到的,你可能不想使用这些。在这种情况下,我的投票是IntelliJ jetbrains注释!