我希望使我的代码更具可读性,以及使用工具,如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
在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;}
}
安卓
这个答案是Android特有的。Android有一个支持包叫做support-annotations。它提供了几十个Android特定的注释,也提供了常见的注释,如NonNull, Nullable等。
要添加support-annotations包,在build.gradle中添加以下依赖项:
compile 'com.android.support:support-annotations:23.1.1'
然后使用:
import android.support.annotation.NonNull;
void foobar(@NonNull Foo bar) {}
在等待上游(Java 8?)整理这些注释时,您还可以定义自己的项目本地@NotNull和@Nullable注释。这在使用Java SE时也很有用,因为默认情况下javax.validation.constraints是不可用的。
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 {}
不可否认,这主要是为了装饰或未来的目的,因为上面显然没有为这些注释的静态分析增加任何支持。