Since JSR 305 (whose goal was to standardize @NonNull and @Nullable) has been dormant for several years, I'm afraid there is no good answer. All we can do is to find a pragmatic solution and mine is as follows:
Syntax
From a purely stylistic standpoint I would like to avoid any reference to IDE, framework or any toolkit except Java itself.
This rules out:
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
Which leaves us with either javax.validation.constraints or javax.annotation. The former comes with JEE. If this is better than javax.annotation, which might come eventually with JSE or never at all, is a matter of debate. I personally prefer javax.annotation because I wouldn't like the JEE dependency.
This leaves us with
javax.annotation
which is also the shortest one.
There is only one syntax which would even be better: java.annotation.Nullable. As other packages graduated from javax to java in the past, the javax.annotation would be a step in the right direction.
Implementation
I was hoping that they all have basically the same trivial implementation, but a detailed analysis showed that this is not true.
First for the similarities:
The @NonNull annotations all have the line
public @interface NonNull {}
except for
org.jetbrains.annotations which calls it @NotNull and has a trivial implementation
javax.annotation which has a longer implementation
javax.validation.constraints which also calls it @NotNull and has an implementation
The @Nullableannotations all have the line
public @interface Nullable {}
except for (again) the org.jetbrains.annotations with their trivial implementation.
For the differences:
A striking one is that
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
all have runtime annotations (@Retention(RUNTIME)), while
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
are only compile time (@Retention(CLASS)).
As described in this SO answer the impact of runtime annotations is smaller than one might think, but they have the benefit of enabling tools to do runtime checks in addition to the compile time ones.
Another important difference is where in the code the annotations can be used. There are two different approaches. Some packages use JLS 9.6.4.1 style contexts. The following table gives an overview:
Package
FIELD
METHOD
PARAMETER
LOCAL_VARIABLE
android.support.annotation
✔️
✔️
✔️
edu.umd.cs.findbugs.annotations
✔️
✔️
✔️
✔️
org.jetbrains.annotation
✔️
✔️
✔️
✔️
lombok
✔️
✔️
✔️
✔️
javax.validation.constraints
✔️
✔️
✔️
org.eclipse.jdt.annotation, javax.annotation and org.checkerframework.checker.nullness.qual use the contexts defined in JLS 4.11, which is in my opinion the right way to do it.
This leaves us with
javax.annotation
org.checkerframework.checker.nullness.qual
in this round.
Code
To help you to compare further details yourself I list the code of every annotation below. To make comparison easier I removed comments, imports and the @Documented annotation. (they all had @Documented except for the classes from the Android package). I reordered the lines and @Target fields and normalized the qualifications.
package android.support.annotation;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER})
public @interface NonNull {}
The following two packages have no @Nullable, so I list them separately; Lombok has a pretty boring @NonNull. In javax.validation.constraints the @NonNull is actually a @NotNull and it has a longish implementation.
I very much like the Checker Framework, which is an implementation of type annotations (JSR-308) which is used to implement defect checkers like a nullness checker. I haven't really tried any others to offer any comparison, but I've been happy with this implementation.
I'm not affiliated with the group that offers the software, but I am a fan.
Four things I like about this system:
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.
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!
According to the Java 7 features list JSR-308 type annotations are deferred to Java 8. JSR-305 annotations are not even mentioned.
There is a bit of info on the state of JSR-305 in an appendix of the latest JSR-308 draft. This includes the observation that JSR-305 annotations seem to be abandoned. The JSR-305 page also shows it as "inactive".
In the mean time, the pragmatic answer is to use the annotation types that are supported by the most widely used tools ... and be prepared to change them if the situation changes.
In fact, JSR-308 does not define any annotation types/classes, and it looks like they think it is out of scope. (And they are right, given the existence of JSR-305).
However, if JSR-308 really looks like making it into Java 8, it wouldn't surprise me if interest in JSR-305 revived. AFAIK, the JSR-305 team hasn't formally abandoned their work. They have just been quiet for 2+ years.
It is interesting that Bill Pugh (the tech lead for JSR-305) is one of the guy behind FindBugs.
支持库本身也带有这些注释 注解,因此作为支持库的用户,Android Studio 会 已经检查您的代码并根据这些标记潜在的问题 注释。
For Android projects you should use android.support.annotation.NonNull and android.support.annotation.Nullable. These and other helpful Android-specific annotations are available in the Support Library.
The support library itself has also been annotated with these annotations, so as a user of the support library, Android Studio will already check your code and flag potential problems based on these annotations.
public Person createPerson(
@NonNull String firstname,
@NonNull String lastname
) {
// even though parameters annotated as NonNull, library clients might call with null.
if (firstname == null) throw new IllagalArgumentException(...);
if (lastname == null) throw new IllagalArgumentException(...);
return doCreatePerson(fistname, lastname, nickname);
}
这有助于客户端不传递 null(编写正确的代码),同时在传递 null 时返回有用的错误。
Distinguish between static analysis and runtime analysis. Use static analysis for internal stuff, and runtime analysis for the public boundaries of your code.
For things that should not be null:
Runtime check: Use "if (x == null) ..." (zero dependency) or @javax.validation.NotNull (with bean validation) or @lombok.NonNull (plain and simple) or guavas Preconditions.checkNotNull(...)
Use Optional for method return types (only). Either Java8 or Guava.
Static check: Use an @NonNull annotation
Where it fits, use @...NonnullByDefault annotations on class or package level. Create these annotations yourself (examples are easy to find).
Else, use @...CheckForNull on method returns to avoid NPEs
This should give the best result: warnings in the IDE, errors by Findbugs and checkerframework, meaningful runtime exceptions.
Do not expect static checks to be mature, their naming is not standardized and different libraries and IDEs treat them differently, ignore them. The JSR305 javax.annotations.* classes look like standard, but they are not, and they cause split packages with Java9+.
Some notes explanations:
Findbugs/spotbugs/jsr305 annotations with package javax.validation.* clash with other modules in Java9+, also possibly violate Oracle license
jetbrains @NotNull name conflicts with @javax.validation.NotNull.
jetbrains, eclipse or checkersframework annotations for static checking have the advantage over javax.annotations that they do not clash with other modules in Java9 and higher
@javax.annotations.Nullable does not mean to Findbugs/Spotbugs what you (or your IDE) think it means. Findbugs will ignore it (on members). Sad, but true (https://sourceforge.net/p/findbugs/bugs/1181)
For static checking outside an IDE, 2 free tools exist: Spotbugs(formerly Findbugs) and checkersframework.
The Eclipse library has @NonNullByDefault, jsr305 only has @ParametersAreNonnullByDefault. Those are mere convenience wrappers applying base annotations to everything in a package (or class), you can easily create your own. This can be used on package. This may conflict with generated code (e.g. lombok).
Using lombok as an exported dependency should be avoided for libraries that you share with other people, the less transitive dependencies, the better
Using Bean validation framework is powerful, but requires high overhead, so that's overkill just to avoid manual null checking.
Using Optional for fields and method parameters is controversial (you can find articles about it easily)
Android null annotations are part of the Android support library, they come with a whole lot of other classes, and don't play nicely with other annotations/tools
Before Java9, this is my recommendation:
// file: package-info.java
@javax.annotation.ParametersAreNonnullByDefault
package example;
// file: PublicApi
package example;
public interface PublicApi {
Person createPerson(
// NonNull by default due to package-info.java above
String firstname,
String lastname);
}
// file: PublicApiImpl
public class PublicApiImpl implements PublicApi {
public Person createPerson(
// In Impl, handle cases where library users still pass null
@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);
}
}
Note that there is no way to make Spotbugs raise a warning when a nullable method parameter is dereferenced (at the time of writing, version 3.1 of Spotbugs). Maybe checkerframework can do that.
Sadly these annotations do not distinguish between the cases of a public method of a library with arbitrary callsites, and non-public methods where each callsite can be known. So the double meaning of: "Indicate that null is undesired, but prepare for null being passed nevertheless" is not possible in a single declaration, hence the above example has different annotations for the interface and the implementation.
For cases where the split interface approach is not practical, the following approach is a compromise:
public Person createPerson(
@NonNull String firstname,
@NonNull String lastname
) {
// even though parameters annotated as NonNull, library clients might call with null.
if (firstname == null) throw new IllagalArgumentException(...);
if (lastname == null) throw new IllagalArgumentException(...);
return doCreatePerson(fistname, lastname, nickname);
}
This helps clients to not pass null (writing correct code), while returning useful errors if they do.
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
{
}
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.
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 308is 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
JSpecify will be the way to go (when it's ready enough). In fact: their presentation actively links to this very question and specifies that their goal is for it to finally have a good answer.
It has major participants like Android, Guava and Kotlin.
newer projects should probably use jakarta.annotation-api (jakarta.annotation package). It is linked from now read-only javax.annotation repo and fits into the new jakarta ecosystem that aims to free the community from all the javax related headaches.
Just pointing out that the Java Validation API (javax.validation.constraints.*) doesn't come with a @Nullable annotation, which is very valuable in a static analysis context. It makes sense for runtime bean validation as this is the default for any non-primitive field in Java (i.e. nothing to validate/enforce). For the purposes stated that should weigh towards the alternatives.
There are already too many answers here, but (a) it's 2019, and there's still no "standard" Nullable and (b) no other answer references Kotlin.
The reference to Kotlin is important, because Kotlin is 100% interoperable with Java and it has a core Null Safety feature. When calling Java libraries, it can take advantage of those annotations to let Kotlin tools know if a Java API can accept or return null.
As far as I know, the only Nullable packages compatible with Kotlin are org.jetbrains.annotations and android.support.annotation (now androidx.annotation). The latter is only compatible with Android so it can't be used in non-Android JVM/Java/Kotlin projects. However, the JetBrains package works everywhere.
So if you develop Java packages that should also work in Android and Kotlin (and be supported by Android Studio and IntelliJ), your best choice is probably the JetBrains package.
Unfortunately, JSR 308 will not add more values than this project local Not Null suggestion here
Java 8 will not come with a single default annotation or its own Checker framework. Similar to Find-bugs or JSR 305, this JSR is poorly maintained by a small bunch of mostly academic teams.
No commercial power behind it, thus JSR 308 launches EDR 3 (Early Draft Review at JCP) NOW, while Java 8 is supposed to ship in less than 6 months:-O Similar to 310 btw. but unlike 308 Oracle has taken charge of that now away from its founders to minimize harm it'll do to the Java Platform.
Every project, vendor and academic class like the ones behind the Checker Framework and JSR 308 will create its own proprietary checker annotation.
Making source code incompatible for years to come, until a few popular compromises could be found and maybe added to Java 9 or 10, or via frameworks like Apache Commons or Google Guava;-)
This answer is Android specific. Android has support package called support-annotations. This provides dozens of Android specific annotations and also provides common ones like NonNull, Nullable etc.
To add support-annotations package, add the following dependency in your build.gradle:
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;}
}
There is another way to do this in Java 8. I am doing 2 things to accomplish what I needed:
Making nullable fields explicit with types by wrapping nullable fields with java.util.Optional
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?
Recommended option given that it is not best practice to use Optional in arguments, we need 2 constructors:
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;}
}
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 {}
While waiting for this to be sorted out upstream (Java 8?), you could also just define your own project-local @NotNull and @Nullable annotations. This can be useful also in case you're working with Java SE, where javax.validation.constraintsisn't available by default.
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 {}
This would admittedly largely be for decorative or future-proofing purposes, since the above obviously doesn't in and of itself add any support for the static analysis of these annotations.
@Service
@Validated
public class MyServiceImpl implements MyService {
@Override
public Something doSomething(@NotNull String myParameter) {
// No need to do something like assert myParameter != null
}
}
If you are building your application using Spring Framework I would suggest using javax.validation.constraints.NotNull comming from Beans Validation packaged in following dependency:
The main advantage of this annotation is that Spring provides support for both method parameters and class fields annotated with javax.validation.constraints.NotNull. All you need to do to enable support is:
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):
provide MethodValidationPostProcessor to spring's context
@Configuration
@ValidationConfig
public class ValidationConfig implements MyService {
@Bean
public MethodValidationPostProcessor providePostProcessor() {
return new MethodValidationPostProcessor()
}
}
@Service
@Validated
public class MyServiceImpl implements MyService {
@Override
public Something doSomething(@NotNull String myParameter) {
// No need to do something like assert myParameter != null
}
}
When you try calling method doSomething and pass null as the parameter value, spring (by means of HibernateValidator) will throw ConstraintViolationException. No need for manuall work here.
You can also validate return values.
Another important benefit of javax.validation.constraints.NotNull comming for Beans Validation Framework is that at the moment it is still developed and new features are planned for new version 2.0.
What about @Nullable? There is nothing like that in Beans Validation 1.1. Well, I could arguee that if you decide to use @NotNull than everything which is NOT annotated with @NonNull is effectively "nullable", so the @Nullable annotation is useless.
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.)
If you're developing for android, you're somewhat tied to Eclipse (edit: at time of writing, not anymore), which has its own annotations. It's included in Eclipse 3.8+ (Juno), but disabled by default.
You can enable it at Preferences > Java > Compiler > Errors/Warnings > Null analysis (collapsable section at the bottom).
Check "Enable annotation-based null analysis"
http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage has recommendations on settings. However, if you have external projects in your workspace (like the facebook SDK), they may not satisfy those recommendations, and you probably don't want to fix them with each SDK update ;-)
I use:
Null pointer access: Error
Violation of null specification: Error (linked to point #1)
Potential null pointer access: Warning (otherwise facebook SDK would have warnings)
Conflict between null annotations and null inference: Warning (linked to point #3)
IDE (Intellij) 将突出显示违反 null 条件的代码。如果设置正确,每个开发人员都可以假设字段、参数和返回值必须不为 null,除非有 @Nullable 注解。如需了解更多信息,请查看这篇文章。
If you are using Spring 5.x / SpringBoot 2.x you should definitely use the Spring annotations (org.springframework.lang), as they provide you a default package-wide null check with the annotations @NonNullFields and @NonNullApi. You will not even have a clash with other NotNull/NonNull annotations from other dependencies, as you are using @NonNullFields/@NonNullApi. The annotations must be used in a file called package-info.java which is placed in the root directory of the package:
To exclude certain fields, parameters, or return values from the null check, just explicitly use the @Nullable annotation. Instead of using @NonNullFields/@NonNullApi you could also set @NonNull everywhere, but probably it is better to activate null checks with @NonNullFields/@NonNullApi by default and only do specific exceptions with @Nullable.
The IDE (Intellij) will highlight code that violates the null conditions. If set up correctly, every developer can assume that fields, parameters and return values must be not null, unless there is a @Nullable annotation. For more information check out this article.
Spring 5 has @NonNullApi at the package level. This seems like a convenient choice for a project that already has Spring dependencies. All fields, parameters and return values default to @NonNull and @Nullable can be applied in the few places that differ.
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.
发布评论
评论(26)
自 JSR 305(其目标是标准化
@NonNull
和@Nullable
) 已经蛰伏了好几年了,恐怕还没有好的答案。我们所能做的就是找到一个务实的解决方案,我的解决方案如下:语法
从纯粹风格的角度来看,我希望避免引用除 Java 本身之外的 IDE、框架或任何工具包。
这排除了:
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
注释都具有该行,除了
org.jetbrains.annotations
,它称为@NotNull
并且有一个简单的实现javax.annotation
,它有一个更长的实现javax.validation.constraints
,它也称为@NotNull
并且有一个实现@可空注释都具有该行,
除了 org.jetbrains.annotations 及其简单的实现(再次)。
对于差异:
一个引人注目的地方是
具有运行时注释 (
@Retention(RUNTIME)
),而android.support.annotation
edu.umd.cs.findbugs.annotations
org. eclipse.jdt.annotation
org.jetbrains.annotations
只是编译时 (
@Retention(CLASS)
)。正如这个答案中所述,运行时注释的影响
比人们想象的要小,但它们有好处
使工具能够进行运行时检查
编译时的。
另一个重要的区别是可以在代码中的什么位置使用注释。
有两种不同的方法。某些包使用 JLS 9.6.4.1 样式上下文。下表给出了概述:
org.eclipse.jdt.annotation
、javax.annotation
和org.checkerframework.checker.nullness.qual
使用中定义的上下文JLS 4.11,这是我认为正确的做法是正确的。
这使得我们在这一轮中只剩下
javax.annotation
org.checkerframework.checker.nullness.qual
。
代码
为了帮助您自己比较更多细节,我在下面列出了每个注释的代码。
为了使比较更容易,我删除了注释、导入和
@Documented
注释。(除了 Android 包中的类之外,它们都有
@Documented
)。我对行和@Target 字段进行了重新排序,并对限定条件进行了规范化。
为了完整起见,这里是@Nullable的实现:
以下两个包没有@Nullable,所以我单独列出它们; Lombok 有一个非常无聊的
@NonNull
。在 javax.validation.constraints 中,@NonNull 实际上是一个 @NotNull
而且它的实施时间较长。
支持
根据我的经验,
javax.annotation
至少受到 Eclipse 和 Checker Framework 的开箱即用支持。总结
我理想的注释是带有 Checker Framework 实现的
java.annotation
语法。如果您不打算使用 Checker 框架,则
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
来自findbugs-注释-1.0.0.jar
org.eclipse.jdt.annotation
来自org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
来自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提交
validation-api-1.0.0.GA-sources.jar
的f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
Since JSR 305 (whose goal was to standardize
@NonNull
and@Nullable
) has been dormant for several years, I'm afraid there is no good answer. All we can do is to find a pragmatic solution and mine is as follows:Syntax
From a purely stylistic standpoint I would like to avoid any reference to IDE, framework or any toolkit except Java itself.
This rules out:
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
Which leaves us with either
javax.validation.constraints
orjavax.annotation
.The former comes with JEE. If this is better than
javax.annotation
, which might come eventually with JSE or never at all, is a matter of debate.I personally prefer
javax.annotation
because I wouldn't like the JEE dependency.This leaves us with
javax.annotation
which is also the shortest one.
There is only one syntax which would even be better:
java.annotation.Nullable
. As other packages graduatedfrom
javax
tojava
in the past, the javax.annotation wouldbe a step in the right direction.
Implementation
I was hoping that they all have basically the same trivial implementation,
but a detailed analysis showed that this is not true.
First for the similarities:
The
@NonNull
annotations all have the lineexcept for
org.jetbrains.annotations
which calls it@NotNull
and has a trivial implementationjavax.annotation
which has a longer implementationjavax.validation.constraints
which also calls it@NotNull
and has an implementationThe
@Nullable
annotations all have the lineexcept for (again) the
org.jetbrains.annotations
with their trivial implementation.For the differences:
A striking one is that
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
all have runtime annotations (
@Retention(RUNTIME)
), whileandroid.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
are only compile time (
@Retention(CLASS)
).As described in this SO answer the impact of runtime annotations
is smaller than one might think, but they have the benefit
of enabling tools to do runtime checks in addition to the
compile time ones.
Another important difference is where in the code the annotations can be used.
There are two different approaches. Some packages use JLS 9.6.4.1 style contexts. The following table gives an overview:
org.eclipse.jdt.annotation
,javax.annotation
andorg.checkerframework.checker.nullness.qual
use the contexts defined inJLS 4.11, which is in my opinion the right way to do it.
This leaves us with
javax.annotation
org.checkerframework.checker.nullness.qual
in this round.
Code
To help you to compare further details yourself I list the code of every annotation below.
To make comparison easier I removed comments, imports and the
@Documented
annotation.(they all had
@Documented
except for the classes from the Android package).I reordered the lines and
@Target
fields and normalized the qualifications.For completeness, here are the
@Nullable
implementations:The following two packages have no
@Nullable
, so I list them separately; Lombok has a pretty boring@NonNull
.In
javax.validation.constraints
the@NonNull
is actually a@NotNull
and it has a longish implementation.
Support
From my experience,
javax.annotation
is at least supported by Eclipse and the Checker Framework out of the box.Summary
My ideal annotation would be the
java.annotation
syntax with the Checker Framework implementation.If you don't intend to use the Checker Framework the
javax.annotation
(JSR-305) is still your best bet for the time being.If you are willing to buy into the Checker Framework just use
their
org.checkerframework.checker.nullness.qual
.Sources
android.support.annotation
fromandroid-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
fromfindbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation
fromorg.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
fromjetbrains-annotations-13.0.jar
javax.annotation
fromgwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual
fromchecker-framework-2.1.9.zip
lombok
fromlombok
commitf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
fromvalidation-api-1.0.0.GA-sources.jar
我非常喜欢 Checker Framework,它是类型注释的实现(JSR-308),用于实现缺陷检查器,例如空值检查器。我还没有真正尝试过任何其他人来提供任何比较,但我对这个实现很满意。
我不属于提供该软件的组织,但我是该软件的粉丝。
我喜欢这个系统的四点:
它有一个针对 nullness 的缺陷检查器 (@可空),但也有 不变性 和 实习(和其他)。我使用第一个(无效),并尝试使用第二个(不变性/IGJ)。我正在尝试第三种,但我不确定是否可以长期使用它。我还不相信其他检查器的一般用途,但很高兴知道该框架本身是一个用于实现各种附加注释和检查器的系统。
空值检查的默认设置效果很好:除局部变量外非空 (NNEL) 。基本上,这意味着默认情况下检查器会将除局部变量之外的所有内容(实例变量、方法参数、泛型类型等)视为默认情况下具有 @NonNull 类型。根据文档:
<块引用>
NNEL 默认值会导致代码中显式注释的数量最少。
如果 NNEL 不适合您,您可以为类或方法设置不同的默认值。
此框架允许您与一起使用,而无需创建对该框架的依赖< /a> 通过将注释括在注释中:例如
/*@Nullable*/
。这很好,因为您可以注释和检查库或共享代码,但仍然能够在不使用该框架的另一个项目中使用该库/共享代码。这是一个很好的功能。我已经习惯了使用它,尽管我现在倾向于在我的所有项目上启用 Checker 框架。该框架有一种方法可以注释您使用的尚未注释的 API通过使用存根文件来消除无效性。
I very much like the Checker Framework, which is an implementation of type annotations (JSR-308) which is used to implement defect checkers like a nullness checker. I haven't really tried any others to offer any comparison, but I've been happy with this implementation.
I'm not affiliated with the group that offers the software, but I am a fan.
Four things I like about this system:
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:
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.
我使用 IntelliJ,因为我主要关心 IntelliJ 标记可能产生 NPE 的事物。我同意 JDK 中没有标准注释是令人沮丧的。有传言要添加它,它可能会进入 Java 7。在这种情况下,就会有更多的选择!
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!
根据 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 团队还没有正式放弃他们的工作。他们已经安静了两年多了。
有趣的是,Bill Pugh(JSR-305 的技术负责人)是 FindBugs 背后的人之一。
According to the Java 7 features list JSR-308 type annotations are deferred to Java 8. JSR-305 annotations are not even mentioned.
There is a bit of info on the state of JSR-305 in an appendix of the latest JSR-308 draft. This includes the observation that JSR-305 annotations seem to be abandoned. The JSR-305 page also shows it as "inactive".
In the mean time, the pragmatic answer is to use the annotation types that are supported by the most widely used tools ... and be prepared to change them if the situation changes.
In fact, JSR-308 does not define any annotation types/classes, and it looks like they think it is out of scope. (And they are right, given the existence of JSR-305).
However, if JSR-308 really looks like making it into Java 8, it wouldn't surprise me if interest in JSR-305 revived. AFAIK, the JSR-305 team hasn't formally abandoned their work. They have just been quiet for 2+ years.
It is interesting that Bill Pugh (the tech lead for JSR-305) is one of the guy behind FindBugs.
对于 Android 项目,您应该使用
android.support.annotation.NonNull
和android.support.annotation.Nullable
。 支持库中提供了这些以及其他有用的 Android 特定注释。来自 http://tools.android.com/tech-docs/support-annotations:
For Android projects you should use
android.support.annotation.NonNull
andandroid.support.annotation.Nullable
. These and other helpful Android-specific annotations are available in the Support Library.From http://tools.android.com/tech-docs/support-annotations:
区分静态分析和运行时分析。对内部内容使用静态分析,对代码的公共边界使用运行时分析。
对于不应该为 null 的内容:
运行时检查:使用“if (x == null) ...”(零依赖)或 @javax.validation.NotNull(使用 bean 验证)或 @lombok.NonNull(普通)和简单)或番石榴 Preconditions.checkNotNull(...)
静态检查:使用@NonNull 注释
这应该会给出最好的结果:IDE 中的警告、Findbugs 和 checkerframework 的错误、有意义的运行时异常。
不要指望静态检查会成熟,它们的命名不规范,不同的库和 IDE 对待它们的方式不同,忽略它们。 JSR305 javax.annotations.* 类看起来像标准的,但实际上并非如此,并且它们会导致与 Java9+ 的包分割。
一些注释解释:
在 Java9 之前,这是我的建议:
请注意,当取消引用可为空的方法参数时,没有办法让 Spotbugs 发出警告(在撰写本文时,Spotbugs 版本为 3.1)。也许 checkerframework 可以做到这一点。
遗憾的是,这些注释无法区分具有任意调用点的库的公共方法和每个调用点已知的非公共方法的情况。因此,“指示不需要 null,但仍要为传递 null 做好准备”的双重含义在单个声明中是不可能的,因此上面的示例对接口和实现有不同的注释。
对于拆分接口方法不实用的情况,以下方法是一种折衷方法:
这有助于客户端不传递 null(编写正确的代码),同时在传递 null 时返回有用的错误。
Distinguish between static analysis and runtime analysis. Use static analysis for internal stuff, and runtime analysis for the public boundaries of your code.
For things that should not be null:
Runtime check: Use "if (x == null) ..." (zero dependency) or @javax.validation.NotNull (with bean validation) or @lombok.NonNull (plain and simple) or guavas Preconditions.checkNotNull(...)
Static check: Use an @NonNull annotation
This should give the best result: warnings in the IDE, errors by Findbugs and checkerframework, meaningful runtime exceptions.
Do not expect static checks to be mature, their naming is not standardized and different libraries and IDEs treat them differently, ignore them. The JSR305 javax.annotations.* classes look like standard, but they are not, and they cause split packages with Java9+.
Some notes explanations:
Before Java9, this is my recommendation:
Note that there is no way to make Spotbugs raise a warning when a nullable method parameter is dereferenced (at the time of writing, version 3.1 of Spotbugs). Maybe checkerframework can do that.
Sadly these annotations do not distinguish between the cases of a public method of a library with arbitrary callsites, and non-public methods where each callsite can be known. So the double meaning of: "Indicate that null is undesired, but prepare for null being passed nevertheless" is not possible in a single declaration, hence the above example has different annotations for the interface and the implementation.
For cases where the split interface approach is not practical, the following approach is a compromise:
This helps clients to not pass null (writing correct code), while returning useful errors if they do.
如果有人只是在寻找 IntelliJ 类:您可以使用以下命令从 Maven 存储库中获取它们
If anyone is just looking for the IntelliJ classes: you can get them from the maven repository with
JSR305和FindBugs是同一个人编写的。两者都维护得很差,但都是标准的,并且受到所有主要 IDE 的支持。好消息是它们按原样运行良好。
以下是如何默认将 @Nonnull 应用于所有类、方法和字段。
请参阅 https://stackoverflow.com/a/13319541/14731 和 https://stackoverflow.com/a/9256595/14731
@NotNullByDefault
2.为每个包添加注解:
package- info.java
更新:截至 2012 年 12 月 12 日 JSR 305 被列为“休眠”。根据文档:
看起来JSR 308正在将其纳入JDK 8,尽管JSR确实不定义@NotNull,附带的
Checkers Framework
会定义。在撰写本文时,Maven 插件由于以下错误而无法使用:https:// /github.com/typetools/checker-framework/issues/183JSR305 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
@NotNullByDefault
2. Add the annotation to each package:
package-info.java
UPDATE: As of December 12th, 2012 JSR 305 is listed as "Dormant". According to the documentation:
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/183JSpecify 将是可行的方法(当它足够准备好时)。事实上:他们的演示文稿主动链接到这个问题,并指定他们的目标是最终得到一个好的答案。
它的主要参与者有 Android、Guava 和 Kotlin。
JSpecify will be the way to go (when it's ready enough). In fact: their presentation actively links to this very question and specifies that their goal is for it to finally have a good answer.
It has major participants like Android, Guava and Kotlin.
较新的项目可能应该使用 jakarta.annotation-api< /a>(
jakarta.annotation
包)。它从现在开始链接为只读 javax.annotation repo 并适合新的 jakarta 生态系统让社区摆脱所有与 javax 相关的麻烦。
newer projects should probably use jakarta.annotation-api (
jakarta.annotation
package).It is linked from now read-only javax.annotation repo and fits into the new jakarta ecosystem that aims to free the community from all the
javax
related headaches.Eclipse 也有自己的注释。
有关详细信息,请参阅 http://wiki.eclipse.org/JDT_Core/Null_Analysis。
Eclipse has also its own annotations.
See at http://wiki.eclipse.org/JDT_Core/Null_Analysis for details.
只是指出 Java 验证 API (
javax.validation.constraints.*
) 没有附带@Nullable
注释,这在静态分析上下文中非常有价值。这对于运行时 bean 验证很有意义,因为这是 Java 中任何非原始字段的默认值(即无需验证/强制执行)。出于所述目的,应权衡替代方案。Just pointing out that the Java Validation API (
javax.validation.constraints.*
) doesn't come with a@Nullable
annotation, which is very valuable in a static analysis context. It makes sense for runtime bean validation as this is the default for any non-primitive field in Java (i.e. nothing to validate/enforce). For the purposes stated that should weigh towards the alternatives.这里已经有太多答案了,但是(a)已经是 2019 年了,仍然没有“标准”
Nullable
以及(b)没有其他答案引用 Kotlin。对 Kotlin 的引用很重要,因为 Kotlin 与 Java 100% 可互操作,并且它具有核心 Null Safety 功能。调用 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:
摇篮:
There are already too many answers here, but (a) it's 2019, and there's still no "standard"
Nullable
and (b) no other answer references Kotlin.The reference to Kotlin is important, because Kotlin is 100% interoperable with Java and it has a core Null Safety feature. When calling Java libraries, it can take advantage of those annotations to let Kotlin tools know if a Java API can accept or return
null
.As far as I know, the only
Nullable
packages compatible with Kotlin areorg.jetbrains.annotations
andandroid.support.annotation
(nowandroidx.annotation
). The latter is only compatible with Android so it can't be used in non-Android JVM/Java/Kotlin projects. However, the JetBrains package works everywhere.So if you develop Java packages that should also work in Android and Kotlin (and be supported by Android Studio and IntelliJ), your best choice is probably the JetBrains package.
Maven:
Gradle:
关于为什么选择 jspecify 的更多详细信息:
jspecify 正在由一个领导小组创建通过 Google:
EISOP 团队,
谷歌,
JetBrains,
元,
微软,
甲骨文、PMD 团队、
声纳,
正方形 ,
优步,
威睿。
他们的目标是创建一个独立于工具的无效注释标准。
解答共识中列出了(最终)使用它的原因
稳定 API 版本 1.0.0 已于 2024 年 7 月 17 日发布。
A bit more details on why to choose jspecify:
jspecify, is being created by a group led by Google:
EISOP Team,
Google,
JetBrains,
Meta ,
Microsoft ,
Oracle ,PMD Team ,
Sonar ,
Square ,
Uber ,
VMware .
They aim to create a tool-independent nullness annotation standard.
They list the reasons to (eventually) use it in their FAQ
Stable API version 1.0.0 has been released on July 17, 2024.
不幸的是,
JSR 308
不会添加比该项目本地 Not Null 建议更多的值Java 8
不会附带单个默认注释或其自己的Checker框架。
与 Find-bugs 或
JSR 305
类似,这个 JSR 由一小群主要是学术团队维护得很差。其背后没有商业力量,因此
JSR 308
立即启动EDR 3
(JCP
的早期草案审查),而Java 8
code> 预计在 6 个月内发货:-O顺便说一句,类似于
310
。但与308
不同的是,Oracle 现在已经从其创始人手中接管了这一事务,以最大程度地减少它对 Java 平台造成的损害。每个项目、供应商和学术课程(例如
Checker Framework
和JSR 308
背后的项目、供应商和学术课程)都将创建自己的专有检查器注释。在未来几年内使源代码不兼容,直到找到一些流行的妥协方案并可能添加到 Java 9 或 10 中,或者通过 Apache Commons 等框架添加/code> 或
Google Guava
;-)Unfortunately,
JSR 308
will not add more values than this project local Not Null suggestion hereJava 8
will not come with a single default annotation or its ownChecker
framework.Similar to Find-bugs or
JSR 305
, this JSR is poorly maintained by a small bunch of mostly academic teams.No commercial power behind it, thus
JSR 308
launchesEDR 3
(Early Draft Review atJCP
) NOW, whileJava 8
is supposed to ship in less than 6 months:-OSimilar to
310
btw. but unlike308 Oracle
has taken charge of that now away from its founders to minimize harm it'll do to the Java Platform.Every project, vendor and academic class like the ones behind the
Checker Framework
andJSR 308
will create its own proprietary checker annotation.Making source code incompatible for years to come, until a few popular compromises could be found and maybe added to
Java 9
or10
, or via frameworks likeApache Commons
orGoogle Guava
;-)Android
这个答案是 Android 特定的。 Android 有一个名为
support-annotations
的支持包。这提供了数十个Android 特定 注释,还提供 常见的,例如NonNull
、Nullable
等。要添加 support-annotations 包,在 build.gradle 中添加以下依赖项:
然后使用:
Android
This answer is Android specific. Android has support package called
support-annotations
. This provides dozens of Android specific annotations and also provides common ones likeNonNull
,Nullable
etc.To add support-annotations package, add the following dependency in your build.gradle:
and then use:
如果您正在开发一个大型项目,您最好创建您自己的
@Nullable
和/或@NotNull
注释。例如:
如果您使用正确的保留策略,则注释将不会在运行时可用。从这个角度来看,这只是一个内部的事情。
尽管这不是一门严格的科学,但我认为使用内部类是最有意义的。
@Nullable
/@NotNull
注释。其他问题(请参阅评论):
如何在 IntelliJ 中进行配置?
If you are working on a big project, you may be better of creating your own
@Nullable
and/or@NotNull
annotations.For example:
If you use the correct retention policy, then the annotations won't be available at runtime. From that point of view, it is just an internal thing.
Even though this is not a strict science, I think it makes most sense to use an internal class for it.
@Nullable
/@NotNull
annotations.Additional Questions (see comments):
How to configure this in IntelliJ ?
在 Java 8 中还有另一种方法可以做到这一点。
我正在做两件事来完成我所需要的:
示例:
编辑:忽略第一个示例,我只是将此处作为评论对话的上下文。此后跳至推荐选项(第二个代码块)。
所以我的问题是,我们在使用java 8时还需要注释吗?
编辑:我后来发现有些人认为在参数中使用
Optional
是一种不好的做法,这里有一个关于优点和缺点的很好的讨论 为什么 Java 8 的Optional 不能在参数中使用推荐的选项,因为在中使用Optional 并不是最佳实践参数,我们需要 2 个构造函数:
There is another way to do this in Java 8.
I am doing 2 things to accomplish what I needed:
java.util.Optional
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).
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 argumentsRecommended option given that it is not best practice to use Optional in arguments, we need 2 constructors:
在等待上游解决这个问题(Java 8?)时,您也可以定义自己的项目本地
@NotNull
和@Nullable
注释。如果您使用 Java SE,这也很有用,其中javax.validation.constraints
默认情况下不可用。诚然,这在很大程度上是出于装饰或面向未来的目的,因为上面的内容显然本身并没有添加对这些注释的静态分析的任何支持。
While waiting for this to be sorted out upstream (Java 8?), you could also just define your own project-local
@NotNull
and@Nullable
annotations. This can be useful also in case you're working with Java SE, wherejavax.validation.constraints
isn't available by default.This would admittedly largely be for decorative or future-proofing purposes, since the above obviously doesn't in and of itself add any support for the static analysis of these annotations.
如果您使用 Spring Framework 构建应用程序,我建议使用来自 Beans Validation 封装在以下依赖中:
该注解的主要优点是 Spring 提供对使用
javax.validation.constraints.NotNull
注解的方法参数和类字段的支持。要启用支持,您所需要做的就是:提供用于 beans 验证的 api jar 和带有 jsr-303/jsr-349 注释验证器实现的 jar(随 Hibernate Validator 5.x 依赖项一起提供):
向 spring 上下文提供 MethodValidationPostProcessor
<前><代码> @Configuration
@ValidationConfig
公共类 ValidationConfig 实现 MyService {
@豆
公共方法验证后处理器提供后处理器(){
返回新的 MethodValidationPostProcessor()
}
}
最后,使用 Spring 的
org.springframework.validation.annotation.Validated
验证将由Spring。示例:
当您尝试调用方法 doSomething 并传递 null 作为参数值时,spring(通过 HibernateValidator)将抛出
ConstraintViolationException
。这里不需要手动工作。您还可以验证返回值。
javax.validation.constraints.NotNull
加入 Beans Validation Framework 的另一个重要好处是,目前它仍在开发中,并且计划在新版本 2.0 中添加新功能。@Nullable
怎么样? Beans Validation 1.1 中没有类似的内容。好吧,我可以说,如果您决定使用@NotNull
,那么所有未用@NonNull
注释的内容实际上都是“可空的”,因此@Nullable< /code> 注释没有用。
If you are building your application using Spring Framework I would suggest using
javax.validation.constraints.NotNull
comming from Beans Validation packaged in following dependency:The main advantage of this annotation is that Spring provides support for both method parameters and class fields annotated with
javax.validation.constraints.NotNull
. All you need to do to enable support is: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):
provide MethodValidationPostProcessor to spring's context
finally you annotate your classes with Spring's
org.springframework.validation.annotation.Validated
and validation will be automatically handled by Spring.Example:
When you try calling method doSomething and pass null as the parameter value, spring (by means of HibernateValidator) will throw
ConstraintViolationException
. No need for manuall work here.You can also validate return values.
Another important benefit of
javax.validation.constraints.NotNull
comming for Beans Validation Framework is that at the moment it is still developed and new features are planned for new version 2.0.What about
@Nullable
? There is nothing like that in Beans Validation 1.1. Well, I could arguee that if you decide to use@NotNull
than everything which is NOT annotated with@NonNull
is effectively "nullable", so the@Nullable
annotation is useless.IntelliJ 的好处之一是您不需要使用它们的注释。您可以自己编写,也可以使用您喜欢的任何其他工具。您甚至不限于单一类型。如果您使用的两个库使用不同的
@NotNull
注释,您可以告诉 IntelliJ 使用这两个库。为此,请转到“配置检查”,单击“常量条件和例外”检查,然后单击“配置检查”按钮。我尽可能使用 Nullness Checker,因此我设置 IntelliJ 来使用这些注释,但您可以让它与您想要的任何其他工具一起使用。 (我对其他工具没有意见,因为我多年来一直使用 IntelliJ 的检查,并且我喜欢它们。)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.)如果您正在为 Android 进行开发,那么您在某种程度上会依赖 Eclipse(编辑:在撰写本文时,不再是了),它有自己的注释。它包含在 Eclipse 3.8+ (Juno) 中,但默认情况下处于禁用状态。
您可以在“首选项”>“启用它”爪哇>编译器>错误/警告>空分析(底部可折叠部分)。
选中“启用基于注释的空分析”
http://wiki.eclipse.org/JDT_Core/Null_Analysis#使用有设置建议。但是,如果您的工作区中有外部项目(例如 facebook SDK),它们可能不满足这些建议,并且您可能不想在每次 SDK 更新时修复它们;-)
我使用:
If you're developing for android, you're somewhat tied to Eclipse (edit: at time of writing, not anymore), which has its own annotations. It's included in Eclipse 3.8+ (Juno), but disabled by default.
You can enable it at Preferences > Java > Compiler > Errors/Warnings > Null analysis (collapsable section at the bottom).
Check "Enable annotation-based null analysis"
http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage has recommendations on settings. However, if you have external projects in your workspace (like the facebook SDK), they may not satisfy those recommendations, and you probably don't want to fix them with each SDK update ;-)
I use:
如果您使用 Spring 5.x / SpringBoot 2.x,您绝对应该使用 Spring 注释 (org.springframework.lang),因为它们通过注释
@NonNullFields
和@NonNullApi
。当您使用@NonNullFields/@NonNullApi
时,您甚至不会与其他依赖项中的其他NotNull/NonNull
注释发生冲突。注释必须在名为 package-info.java 的文件中使用,该文件位于包的根目录中:要从 null 检查中排除某些字段、参数或返回值,只需显式使用
@Nullable< /代码> 注释。您也可以在任何地方设置
@NonNull
,而不是使用@NonNullFields/@NonNullApi
,但最好使用@NonNullFields/@NonNullApi
激活 null 检查默认情况下,仅使用@Nullable
执行特定异常。IDE (Intellij) 将突出显示违反 null 条件的代码。如果设置正确,每个开发人员都可以假设字段、参数和返回值必须不为 null,除非有
@Nullable
注解。如需了解更多信息,请查看这篇文章。If you are using Spring 5.x / SpringBoot 2.x you should definitely use the Spring annotations (org.springframework.lang), as they provide you a default package-wide null check with the annotations
@NonNullFields
and@NonNullApi
. You will not even have a clash with otherNotNull/NonNull
annotations from other dependencies, as you are using@NonNullFields/@NonNullApi
. The annotations must be used in a file called package-info.java which is placed in the root directory of the package:To exclude certain fields, parameters, or return values from the null check, just explicitly use the
@Nullable
annotation. Instead of using@NonNullFields/@NonNullApi
you could also set@NonNull
everywhere, but probably it is better to activate null checks with@NonNullFields/@NonNullApi
by default and only do specific exceptions with@Nullable
.The IDE (Intellij) will highlight code that violates the null conditions. If set up correctly, every developer can assume that fields, parameters and return values must be not null, unless there is a
@Nullable
annotation. For more information check out this article.现在sun没有自己的了吗?这是什么:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm
这似乎是用过去几年我使用过的所有 Java 版本。
编辑:正如下面的评论中提到的,您可能不想使用这些。在这种情况下,我投票给 IntelliJ jetbrains 注释!
Doesn't sun have their own now? What's this:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm
This seems to be packaged with all the versions of Java I've used within the last few years.
Edit: As mentioned in the comments below, you probably don't want to use these. In that case, my vote is for the IntelliJ jetbrains annotations!
Spring 5 在包级别有@NonNullApi。对于已经具有 Spring 依赖项的项目来说,这似乎是一个方便的选择。所有字段、参数和返回值默认为 @NonNull 和 @Nullable 可以应用于少数不同的地方。
文件 package-info.java:
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations
Spring 5 has @NonNullApi at the package level. This seems like a convenient choice for a project that already has Spring dependencies. All fields, parameters and return values default to @NonNull and @Nullable can be applied in the few places that differ.
File package-info.java:
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations
另一种选择是 ANTLR 4 提供的注释。在 Pull Request #434 之后,包含以下内容的工件
@NotNull
和@Nullable
注解包含一个注解处理器,如果这些属性之一被误用(例如,如果两者都使用),该处理器会生成编译时错误和/或警告应用于同一个项目,或者如果@Nullable
应用于具有原始类型的项目)。注释处理器在软件开发过程中提供额外的保证,确保这些注释的应用所传达的信息是准确的,包括在方法继承的情况下。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.