ตั้งแต่JSR 305 (ซึ่งมีเป้าหมายคือมาตรฐาน@NonNull
และ@Nullable
) อยู่เฉยๆเป็นเวลาหลายปีฉันกลัวว่าจะไม่มีคำตอบที่ดี ทั้งหมดที่เราสามารถทำได้คือการหาวิธีแก้ปัญหาในทางปฏิบัติและของฉันเป็นดังนี้:
วากยสัมพันธ์
จากจุดยืนโวหารล้วนๆฉันต้องการหลีกเลี่ยงการอ้างอิงใด ๆ กับ 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
คำอธิบายประกอบทุกคนมีเส้น
public @interface NonNull {}
ยกเว้น
org.jetbrains.annotations
ซึ่งเรียกมัน@NotNull
และมีการใช้งานเล็กน้อย
javax.annotation
ซึ่งมีการนำไปใช้อีกต่อไป
javax.validation.constraints
ซึ่งเรียกมัน@NotNull
และมีการดำเนินการ
@Nullable
คำอธิบายประกอบทุกคนมีเส้น
public @interface Nullable {}
ยกเว้นสำหรับ (อีกครั้ง) org.jetbrains.annotations
ด้วยการใช้งานเล็กน้อย
สำหรับความแตกต่าง:
สิ่งหนึ่งที่น่าทึ่งก็คือ
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
ทั้งหมดมีหมายเหตุประกอบแบบรันไทม์ ( @Retention(RUNTIME)
) ขณะที่
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
เป็นเพียงการรวบรวมเวลา (@Retention(CLASS)
)
ดังที่อธิบายไว้ในSO นี้คำตอบผลกระทบของหมายเหตุประกอบแบบรันไทม์อาจน้อยกว่าที่คิด แต่มีประโยชน์ในการเปิดใช้งานเครื่องมือเพื่อทำการตรวจสอบรันไทม์นอกเหนือจากเวลารวบรวม
ข้อแตกต่างที่สำคัญอีกประการหนึ่งก็คือตำแหน่งที่สามารถใช้คำอธิบายประกอบในรหัสได้ มีสองวิธีที่แตกต่างกัน บางแพ็คเกจใช้บริบทสไตล์ JLS 9.6.4.1 ตารางต่อไปนี้ให้ภาพรวม:
วิธีฟิลด์พารามิเตอร์ LOCAL_VARIABLE
android.support.annotation XXX
edu.umd.cs.findbugs.annotations XXXX
XXXX. org.jetbrains.annotation
lombok XXXX
javax.validation.constraints XXX
org.eclipse.jdt.annotation
, javax.annotation
และorg.checkerframework.checker.nullness.qual
ใช้บริบทที่กำหนดไว้ใน JLS 4.11 ซึ่งอยู่ในความคิดของฉันวิธีการที่เหมาะสมที่จะทำมัน
สิ่งนี้ทำให้เรามี
javax.annotation
org.checkerframework.checker.nullness.qual
ในรอบนี้
รหัส
เพื่อช่วยให้คุณสามารถเปรียบเทียบรายละเอียดเพิ่มเติมด้วยตัวเองฉันจะแสดงรายการรหัสของคำอธิบายประกอบด้านล่างทุกรายการ เพื่อให้การเปรียบเทียบง่ายขึ้นฉันได้ลบความคิดเห็นการนำเข้าและ@Documented
คำอธิบายประกอบ (พวกเขาทั้งหมด@Documented
ยกเว้นคลาสจากแพ็คเกจ Android) ฉันจัดเรียงบรรทัดและ@Target
ฟิลด์ใหม่และปรับคุณสมบัติให้เป็นมาตรฐาน
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 {}
เพื่อความสมบูรณ์นี่คือการ@Nullable
ใช้งาน:
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 {}
แพ็คเกจสองรายการต่อไปนี้ไม่มี@Nullable
ดังนั้นฉันจึงแยกรายการเหล่านั้นแยกกัน @NonNull
ลอมบอกมีสวยน่าเบื่อ ในjavax.validation.constraints
ความ@NonNull
เป็นจริง@NotNull
และมันก็มีการใช้งานที่ยาวนาน
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();
}
}
สนับสนุน
จากประสบการณ์ของฉันjavax.annotation
อย่างน้อย Eclipse ได้รับการสนับสนุนและ Checker Framework นอกกรอบ
สรุป
บันทึกย่อในอุดมคติของฉันจะเป็นjava.annotation
ไวยากรณ์ที่มีการใช้งาน Checker Framework
หากคุณไม่ต้องการใช้ Checker Framework javax.annotation
( JSR-305 ) ก็ยังเป็นทางออกที่ดีที่สุดของคุณในขณะนี้
org.checkerframework.checker.nullness.qual
หากคุณมีความเต็มใจที่จะซื้อเป็นตัวตรวจสอบกรอบเพียงแค่ใช้ของพวกเขา
แหล่งที่มา
android.support.annotation
จาก android-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
จาก findbugs-annotations-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
กระทำf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
จาก validation-api-1.0.0.GA-sources.jar