Which @NotNull Java annotation should I use?

前端 未结 22 2743
梦如初夏
梦如初夏 2020-11-22 02:44

I\'m looking to make my code more readable as well as use tooling like IDE code inspection and/or static code analysis (FindBugs and Sonar) to avoid NullPointerExceptions.

相关标签:
22条回答
  • 2020-11-22 03:27

    I use the IntelliJ one, because I'm mostly concerned with IntelliJ flagging things that might produce a NPE. I agree that it's frustrating not having a standard annotation in the JDK. There's talk of adding it, it might make it into Java 7. In which case there will be one more to choose from!

    0 讨论(0)
  • 2020-11-22 03:27

    JSR305 and FindBugs are authored by the same person. Both are poorly maintained but are as standard as it gets and are supported by all major IDEs. The good news is that they work well as-is.

    Here is how to apply @Nonnull to all classes, methods and fields by default. See https://stackoverflow.com/a/13319541/14731 and https://stackoverflow.com/a/9256595/14731

    1. Define @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://stackoverflow.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. Add the annotation to each package: package-info.java

    @NotNullByDefault
    package com.example.foo;
    

    UPDATE: As of December 12th, 2012 JSR 305 is listed as "Dormant". According to the documentation:

    A JSR that was voted as "dormant" by the Executive Committee, or one that has reached the end of its natural lifespan.

    It looks like JSR 308 is making it into JDK 8 and although the JSR does not define @NotNull, the accompanying Checkers Framework does. At the time of this writing, the Maven plugin is unusable due to this bug: https://github.com/typetools/checker-framework/issues/183

    0 讨论(0)
  • 2020-11-22 03:27

    One of the nice things about IntelliJ is that you don't need to use their annotations. You can write your own, or you can use those of whatever other tool you like. You're not even limited to a single type. If you're using two libraries that use different @NotNull annotations, you can tell IntelliJ to use both of them. To do this, go to "Configure Inspections", click on the "Constant Conditions & Exceptions" inspection, and hit the "Configure inspections" button. I use the Nullness Checker wherever I can, so I set up IntelliJ to use those annotations, but you can make it work with whatever other tool you want. (I have no opinion on the other tools because I've been using IntelliJ's inspections for years, and I love them.)

    0 讨论(0)
  • 2020-11-22 03:27

    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.

    0 讨论(0)
  • 2020-11-22 03:29

    There is another way to do this in Java 8. I am doing 2 things to accomplish what I needed:

    1. Making nullable fields explicit with types by wrapping nullable fields with java.util.Optional
    2. Checking that all non nullable fields are not null at construction time with java.util.Objects.requireNonNull

    Example:

    Edit: Disregard this 1st example, I'm just leaving here as context of the comments conversation. Skip to recommended option after this (2nd code block).

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

    So my question is, do we even need to annotate when using java 8?

    Edit: I found out later that some consider a bad practice to use Optional in arguments, there is a good discussion with pros and cons here Why should Java 8's Optional not be used in arguments

    Recommended option given that it is not best practice to use Optional in arguments, we need 2 constructors:

      //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();
          }
    
    0 讨论(0)
  • 2020-11-22 03:33

    Eclipse has also its own annotations.

    org.eclipse.jdt.annotation.NonNull
    

    See at http://wiki.eclipse.org/JDT_Core/Null_Analysis for details.

    0 讨论(0)
提交回复
热议问题