Vì JSR 305 (có mục tiêu là tiêu chuẩn hóa @NonNullvà @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.constraintshoặ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.annotationvì 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 @NonNullchú thích đều có dòng
public @interface NonNull {}
ngoại trừ
org.jetbrains.annotationsmà gọi nó @NotNullvà có một thực hiện tầm thường
javax.annotation trong đó thực hiện lâu hơn
javax.validation.constraintsmà cũng gọi nó @NotNullvà có một thực hiện
Các @Nullablechú thích đều có dòng
public @interface Nullable {}
ngoại trừ (một lần nữa) org.jetbrains.annotationsvớ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.annotationVà org.checkerframework.checker.nullness.qualsử 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à @Documentedchú thích. (tất cả họ đều có @Documentedngoại trừ các lớp từ gói Android). Tôi sắp xếp lại các dòng và @Targetcá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 @Nullabletriể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.constraintscác @NonNullthự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
lomboktừ lombokcam kếtf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints từ validation-api-1.0.0.GA-sources.jar