Vì JSR 305 (có mục tiêu là tiêu chuẩn hóa @NonNull
và @Nullable
) đã không hoạt động trong nhiều năm, tôi sợ rằng không có câu trả lời hay. Tất cả những gì chúng ta có thể làm là tìm một giải pháp thực dụng và của tôi là như sau:
Cú pháp
Từ quan điểm hoàn toàn theo phong cách, tôi muốn tránh mọi tham chiếu đến IDE, khung hoặc bất kỳ bộ công cụ nào ngoại trừ chính Java.
Điều này loại trừ:
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
Mà để lại cho chúng tôi với javax.validation.constraints
hoặc javax.annotation
. Các cựu đi kèm với JEE. Nếu điều này tốt hơn javax.annotation
, cuối cùng có thể đến với JSE hoặc không bao giờ, thì đó là vấn đề tranh luận. Cá nhân tôi thích javax.annotation
vì tôi không thích sự phụ thuộc của JEE.
Điều này để lại cho chúng tôi
javax.annotation
cái nào cũng ngắn nhất
Chỉ có một cú pháp thậm chí sẽ tốt hơn : java.annotation.Nullable
. Như các gói tốt nghiệp javax
đểjava
, javax.annotation sẽ là một bước đi đúng hướng.
Thực hiện
Tôi đã hy vọng rằng tất cả chúng đều có cùng một cách thực hiện tầm thường, nhưng một phân tích chi tiết cho thấy điều này không đúng.
Đầu tiên cho sự tương đồng:
Các @NonNull
chú thích đều có dòng
public @interface NonNull {}
ngoại trừ
org.jetbrains.annotations
mà gọi nó @NotNull
và có một thực hiện tầm thường
javax.annotation
trong đó thực hiện lâu hơn
javax.validation.constraints
mà cũng gọi nó @NotNull
và có một thực hiện
Các @Nullable
chú thích đều có dòng
public @interface Nullable {}
ngoại trừ (một lần nữa) org.jetbrains.annotations
với việc thực hiện tầm thường của họ.
Đối với sự khác biệt:
Một trong những nổi bật là
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
tất cả đều có chú thích thời gian chạy ( @Retention(RUNTIME)
), trong khi
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
chỉ là thời gian biên dịch (@Retention(CLASS)
).
Như được mô tả trong câu trả lời SO này , tác động của các chú thích thời gian chạy nhỏ hơn người ta có thể nghĩ, nhưng chúng có lợi ích là cho phép các công cụ thực hiện kiểm tra thời gian chạy ngoài thời gian biên dịch.
Một sự khác biệt quan trọng là nơi mã trong các chú thích có thể được sử dụng. Có hai cách tiếp cận khác nhau. Một số gói sử dụng bối cảnh kiểu JLS 9.6.4.1. Bảng sau đây cung cấp tổng quan:
LELDNH VỰC PHƯƠNG PHÁP PARAMETER LOCAL_VARIABLE
android.support.annotation XXX
edu.umd.cs.findbugs.annotations XXXX
org.jetbrains.annotation XXXX
lXk XXXX
javax.validation.constraint XXX
org.eclipse.jdt.annotation
, javax.annotation
Và org.checkerframework.checker.nullness.qual
sử dụng bối cảnh quy định tại JLS 4.11, đó là theo ý kiến của tôi đúng cách để làm điều đó.
Điều này để lại cho chúng tôi
javax.annotation
org.checkerframework.checker.nullness.qual
trong vòng này.
Mã
Để giúp bạn tự so sánh chi tiết hơn, tôi liệt kê mã của mỗi chú thích bên dưới. Để làm cho việc so sánh dễ dàng hơn, tôi đã xóa các bình luận, nhập khẩu và @Documented
chú thích. (tất cả họ đều có @Documented
ngoại trừ các lớp từ gói Android). Tôi sắp xếp lại các dòng và @Target
các lĩnh vực và bình thường hóa trình độ.
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 {}
Để hoàn thiện, đây là các @Nullable
triển khai:
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 {}
Hai gói sau không có @Nullable
, vì vậy tôi liệt kê chúng một cách riêng biệt; Lombok có một sự nhàm chán @NonNull
. Trong javax.validation.constraints
các @NonNull
thực sự là một @NotNull
và nó có một thi hơi dài.
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();
}
}
Ủng hộ
Theo kinh nghiệm của tôi, javax.annotation
ít nhất được hỗ trợ bởi Eclipse và Khung kiểm tra ra khỏi hộp.
Tóm lược
Chú thích lý tưởng của tôi sẽ là java.annotation
cú pháp với việc triển khai Khung kiểm tra.
Nếu bạn không có ý định sử dụng Khung kiểm tra thì javax.annotation
( JSR-305 ) vẫn là lựa chọn tốt nhất của bạn trong thời điểm hiện tại.
Nếu bạn sẵn sàng mua vào Khung kiểm tra, chỉ cần sử dụng chúng org.checkerframework.checker.nullness.qual
.
Nguồn
android.support.annotation
từ android-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
từ findbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation
từ org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
từ jetbrains-annotations-13.0.jar
javax.annotation
từ gwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual
từ checker-framework-2.1.9.zip
lombok
từ lombok
cam kếtf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
từ validation-api-1.0.0.GA-sources.jar