ฉันควรใช้คำอธิบายประกอบ @NotNull Java ใด


997

ฉันต้องการทำให้โค้ดของฉันอ่านง่ายขึ้นรวมถึงใช้เครื่องมือเช่นการตรวจสอบรหัส IDE และ / หรือการวิเคราะห์รหัสแบบคงที่ (FindBugs และ Sonar) เพื่อหลีกเลี่ยง NullPointerExceptions เครื่องมือจำนวนมากดูไม่เข้ากันกับ@NotNull/ @NonNull/ / @Nonnullหมายเหตุประกอบของแต่ละคนและการแสดงรายการทั้งหมดในรหัสของฉันจะอ่านได้แย่มาก คำแนะนำใดที่ 'ดีที่สุด'? นี่คือรายการคำอธิบายประกอบที่เทียบเท่าที่ฉันพบ:

  • javax.validation.constraints.NotNull
    สร้างขึ้นสำหรับการตรวจสอบความถูกต้องรันไทม์ไม่ใช่การวิเคราะห์แบบคงที่
    เอกสาร

  • edu.umd.cs.findbugs.annotations.NonNull
    ใช้โดยFindBugsวิเคราะห์แบบคงที่และดังนั้นจึง Sonar (ตอนนี้Sonarqube )
    เอกสาร

  • javax.annotation.Nonnull
    สิ่งนี้อาจใช้ได้กับ Findbugs ด้วยเช่นกัน แต่JSR-305ไม่ได้ใช้งาน (ดูเพิ่มเติม: อะไรคือสถานะของ JSR 305? ) แหล่งที่มา

  • org.jetbrains.annotations.NotNull
    ใช้โดย IntelliJ IDEA IDE สำหรับการวิเคราะห์แบบคงที่
    เอกสาร

  • lombok.NonNull
    ใช้ในการควบคุมการสร้างรหัสในโครงการลอมบอก
    คำอธิบายประกอบตัวยึดเนื่องจากไม่มีมาตรฐาน
    แหล่งที่มา , เอกสาร

  • android.support.annotation.NonNull
    คำอธิบายประกอบเครื่องหมายที่มีอยู่ใน Android จัดทำโดยแพคเกจการสนับสนุนคำอธิบายประกอบ
    เอกสาร

  • org.eclipse.jdt.annotation.NonNull
    ใช้โดย Eclipse สำหรับการวิเคราะห์โค้ดแบบคงที่
    เอกสาร


203
apache ควรประดิษฐ์คำอธิบายประกอบที่ "ทั่วไป" และเครื่องมือที่สามารถแปลงเป็นคำอธิบายประกอบอื่น ๆ ได้ การแก้ปัญหาของมาตรฐานที่มากเกินไปคือการสร้างมาตรฐานใหม่
พูดไม่ได้

6
@ โต้แย้งได้หาก apache สร้าง "สามัญ" ใหม่จะมี 56 เวอร์ชันซ้อนทับกับโครงการอื่น และจะไม่เป็นมาตรฐานอยู่ดี (มาตรฐาน! = แพร่หลาย) ควรใช้ทุกอย่างที่เป็นมาตรฐาน javax? * BTW ไม่มี "มาตรฐานมากเกินไป" ในตัวอย่างเหล่านั้นฉันเห็น 1 หรือ 2
ymajoros

6
javax.annotation.Nonnull ทำงานกับ findbugs (เพิ่งทดสอบ) ซึ่งเป็นเหตุผลที่น่าสนใจสำหรับฉันที่จะใช้มัน
Nicolas C

20
ถ้าฉันเพียงแค่เขียน @NotNull com.sun.istack.internal.NotNullมันหมายถึง OMG ...
โธมัสเวลเลอ

3
@MozartBrocchini - ตัวเลือกมีประโยชน์ในกรณีที่คุณอาจเคยใช้ NullObjects พวกเขาไม่ได้พูดถึงจุดมุ่งหมายเดียวกับการใช้คำอธิบายประกอบแบบรันไทม์ \ @NotNull และพวกเขาแนะนำการแกะที่น่าเบื่อออก
เดฟ

คำตอบ:


205

ตั้งแต่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

7
ข้อเสียของjavax.annotationมันคือก.) ขึ้นอยู่กับ JSR ที่ตายแล้วข) ยากที่จะหาสิ่งประดิษฐ์ที่เพียงแค่ให้คำอธิบายประกอบและได้รับการบำรุงรักษา หนึ่งใน findbugs ไม่ได้: search.maven.org/…
robinst

18
จุดต่อjavax.annotationคือว่ามันทำให้เกิดปัญหากับ Java 9 เพราะโมดูลอื่น ๆ ยังมีการเรียนในแพคเกจนั้น (jax-ws)
robinst

10
@kevinarpe: โปรเจ็กต์ Findbugs นั้นตายแล้วและโปรเจ็กต์ตัวตายตัวแทน Spotbugs กำลังลบคำอธิบายประกอบเหล่านั้น: github.com/spotbugs/spotbugs/pull/180
robinst

4
JSR 305ซึ่งน่าจะเป็นมาตรฐานjavax.annotation.NonNullไม่เคยเสร็จสมบูรณ์เพราะข้อมูลจำเพาะนำไปสู่ ​​AWOL มันไม่เกี่ยวอะไรกับการตัดสินใจของ Oracle
Mark Reinhold

5
อีกเหตุผลที่ไม่ควรใช้ jsr305.jar ก็คือเป็นการละเมิดสิทธิ์การใช้งานไบนารีของ Oracle Java: github.com/google/guava/issues/2960
Flow

91

ฉันชอบChecker Frameworkมากซึ่งเป็นการนำไปใช้งานคำอธิบายประกอบประเภท ( JSR-308 ) ซึ่งใช้ในการใช้ตัวตรวจสอบข้อบกพร่องเช่นตัวตรวจสอบความว่างเปล่า ฉันไม่ได้ลองคนอื่นเพื่อเสนอการเปรียบเทียบ แต่ฉันมีความสุขกับการใช้งานนี้

ฉันไม่ได้เกี่ยวข้องกับกลุ่มที่เสนอซอฟต์แวร์ แต่ฉันเป็นแฟน

สี่สิ่งที่ฉันชอบเกี่ยวกับระบบนี้:

  1. แต่ก็มีการตรวจสอบข้อบกพร่องสำหรับnullness (@Nullable) แต่ยังมีคนสำหรับการไม่เปลี่ยนรูปและฝึกงาน (และอื่น ๆ ) ฉันใช้อันแรก (เปล่า) และฉันพยายามที่จะใช้อันที่สอง (immutability / IGJ) ฉันลองใช้อันที่สาม แต่ฉันยังไม่แน่ใจเกี่ยวกับการใช้งานในระยะยาว ฉันยังไม่มั่นใจในประโยชน์ทั่วไปของตัวตรวจสอบอื่น ๆ แต่มันก็ดีที่รู้ว่ากรอบงานนั้นเป็นระบบสำหรับการนำหมายเหตุและตัวตรวจสอบเพิ่มเติมมาใช้อย่างหลากหลาย

  2. การตั้งค่าเริ่มต้นสำหรับการตรวจสอบความว่างเปล่าทำงานได้ดี: ไม่เป็นโมฆะยกเว้นคนในท้องถิ่น (NNEL) โดยทั่วไปนี่หมายความว่าโดยค่าเริ่มต้นตัวตรวจสอบจะปฏิบัติต่อ everyhing (ตัวแปรอินสแตนซ์พารามิเตอร์เมธอดชนิดทั่วไป ฯลฯ ) ยกเว้นตัวแปรโลคัลราวกับว่าพวกเขามีชนิด @NonNull เป็นค่าเริ่มต้น ตามเอกสาร:

    ค่าเริ่มต้น NNEL นำไปสู่การเพิ่มความคิดเห็นที่น้อยที่สุดในรหัสของคุณ

    คุณสามารถตั้งค่าเริ่มต้นที่แตกต่างกันสำหรับชั้นเรียนหรือสำหรับวิธีการถ้า NNEL ไม่ทำงานสำหรับคุณ

  3. กรอบนี้ช่วยให้คุณสามารถใช้งานร่วมกับโดยไม่ต้องสร้างการพึ่งพากรอบได้โดยแนบคำอธิบายประกอบในความคิดเห็น: /*@Nullable*/เช่น นี่เป็นสิ่งที่ดีเพราะคุณสามารถใส่คำอธิบายประกอบและตรวจสอบไลบรารีหรือรหัสที่ใช้ร่วมกันได้ แต่ก็ยังสามารถใช้รหัสห้องสมุด / รหัสที่แชร์ในโครงการอื่นที่ไม่ได้ใช้เฟรมเวิร์ก นี่เป็นคุณสมบัติที่ดี ฉันคุ้นเคยกับการใช้มันมากขึ้นแม้ว่าฉันจะเปิดใช้งาน Checker Framework ในทุกโครงการของฉันในตอนนี้

  4. เฟรมเวิร์กมีวิธีในการเพิ่มความคิดเห็นของAPI ที่คุณใช้ซึ่งยังไม่ได้ใส่คำอธิบายประกอบสำหรับความว่างเปล่าโดยใช้ไฟล์ stub


3
ดูเหมือนดีและฉันต้องการใช้ แต่ไม่สามารถ ทำไมต้อง GPL ไม่สามารถใช้ LGPL แทนได้หรือ
Burkhard

13
ตามคำถามที่พบบ่อย : "สิทธิ์การใช้งาน MIT ที่ได้รับอนุญาตจะมีผลกับรหัสที่คุณอาจต้องการรวมไว้ในโปรแกรมของคุณเองเช่นคำอธิบายประกอบ"
seanf

1
ลิงก์เสียในขณะนี้ แต่ +1 สำหรับคำแนะนำในการใช้ Checker Framework
Paul Wagland

1
เป็นเรื่องน่าเสียดายที่ตัวตรวจสอบความไม่สามารถเปลี่ยนแปลงได้ถูกปล่อยในรุ่นล่าสุด
Franklin Yu

1
ตรวจสอบกรอบนอกจากนี้ยังมีข้อเสนอแนะในออราเคิล Java สอน
Quazi Irfan

55

ฉันใช้ IntelliJ หนึ่งเพราะฉันส่วนใหญ่กังวลกับ IntelliJ การตั้งค่าสถานะสิ่งที่อาจสร้าง NPE ฉันยอมรับว่ามันน่าหงุดหงิดที่ไม่มีหมายเหตุประกอบแบบมาตรฐานใน JDK มีการพูดถึงการเพิ่มมันอาจทำให้มันเป็น Java 7 ในกรณีที่จะมีอีกหนึ่งให้เลือก!


68
อัปเดต: IntelliJ สนับสนุนหมายเหตุประกอบด้านบนทั้งหมดเพื่อเน้นรหัสดังนั้นคุณไม่ จำกัด การเพิ่มความคิดเห็นของ IntelliJ อีกต่อไป: blogs.jetbrains.com/idea/2011/03/ …
Daniel Alexiuc

31
และ Eclipse Juno ก็เช่นกัน!
jFrenetic

5
javax.annotation.Nonnullได้รับการยอมรับอย่างกว้างขวางมากขึ้นใช่ไหม?
Martin

1
@DanielAlexiuc แต่น่าเสียดายที่มันไม่ได้ใช้สำหรับการตรวจสอบรันไทม์ดังนั้นจึงยังมีประโยชน์ในการใช้ JetBrains คน ...
Trejkaz

4
@Trejkaz ตั้งแต่ 2016.3 จะสร้างการตรวจสอบรันไทม์สำหรับสิ่งเหล่านั้นทั้งหมด
Karol S

32

ตามรายการคุณลักษณะของ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 ยังไม่เลิกงานอย่างเป็นทางการ พวกเขาเงียบไปกว่า 2 ปีแล้ว

เป็นที่น่าสนใจว่า Bill Pugh (ผู้นำทางเทคโนโลยีสำหรับ JSR-305) เป็นหนึ่งในคนที่อยู่เบื้องหลัง FindBugs


4
@pst - กำหนดการปัจจุบันสำหรับ Java 8 เพื่อไปยังรุ่นทั่วไปในเดือนกันยายน 2013 - infoq.com/news/2012/04/jdk-8-milestone-release-dates
Stephen C

2
ที่ได้เล็ดรอดถึงมีนาคม 2014 ตอนนี้ - openjdk.java.net/projects/jdk8 JSR 308 รวมอยู่ใน build M7 (ดูใน "104 - คำอธิบายประกอบบนประเภท Java")
สตีเฟ่นซี

28

สำหรับโครงการ Android ที่คุณควรใช้ android.support.annotation.NonNullandroid.support.annotation.Nullableและ เหล่านี้และอื่น ๆ ที่เป็นประโยชน์คำอธิบายประกอบ Android เฉพาะที่มีอยู่ในห้องสมุดสนับสนุน

จาก http://tools.android.com/tech-docs/support-annotations :

ไลบรารีการสนับสนุนนั้นได้รับการเพิ่มความคิดเห็นด้วยคำอธิบายประกอบเหล่านี้ดังนั้นในฐานะผู้ใช้ของไลบรารีการสนับสนุน Android Studio จะตรวจสอบรหัสของคุณและตั้งค่าสถานะปัญหาที่อาจเกิดขึ้นตามคำอธิบายประกอบเหล่านี้


3
มันจะมีประโยชน์ในการให้เหตุผลสำหรับคำแนะนำนั้น
apricot

2
tools.android.com/tech-docs/support-annotations "ไลบรารีการสนับสนุนนั้นได้รับการเพิ่มความคิดเห็นด้วยหมายเหตุประกอบเหล่านี้ดังนั้นในฐานะผู้ใช้ไลบรารีการสนับสนุน Android Studio จะตรวจสอบรหัสของคุณและตั้งค่าสถานะปัญหาที่อาจเกิดขึ้นจากคำอธิบายประกอบเหล่านี้ ."
James Wald

3
BTW Android Studio รองรับ jsr305 พร้อมjavax.annotation.*คำอธิบายประกอบด้วย
CAMOBAP

19

หากใครก็ตามที่กำลังมองหาคลาส IntelliJ: คุณสามารถรับพวกเขาจากที่เก็บ maven ด้วย

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 

นี่คือสิ่งที่ทำให้ Intellij โยนคำเตือนขึ้นมา
คลิกโหวต

รุ่นปัจจุบัน (ตั้งแต่วันที่ 05/2017) คือ 15.0
BamaPookie

คุณถูก. ฉันได้อัปเดตเวอร์ชันแล้ว แม้ว่าฉันเดาว่ามันจะไม่เปลี่ยนแปลงมากนัก
Bruno Eberhard

โปรดทราบว่าคำอธิบายประกอบ JetBrains จะไม่ถูกเก็บไว้สำหรับรันไทม์ดังนั้นตัวอย่างการสนับสนุน Guice @Nullable จึงไม่สามารถใช้งานได้
ปีเตอร์เมเจอร์

18

JSR305 และ FindBugs เขียนโดยบุคคลเดียวกัน ทั้งสองได้รับการบำรุงรักษาไม่ดี แต่มีมาตรฐานตามที่ได้รับและได้รับการสนับสนุนจาก IDE หลักทั้งหมด ข่าวดีก็คือพวกเขาทำงานได้ดีเหมือนที่เป็นอยู่

นี่คือวิธีการใช้ @Nonnull กับคลาสวิธีและฟิลด์ทั้งหมดโดยค่าเริ่มต้น ดูhttps://stackoverflow.com/a/13319541/14731และhttps://stackoverflow.com/a/9256595/14731

  1. กำหนด @NotNullByDefault
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. เพิ่มคำอธิบายประกอบให้กับแต่ละแพ็คเกจ: package-info.java

@NotNullByDefault
package com.example.foo;

ปรับปรุง : ณ วันที่ 12 ธันวาคม 2012 JSR 305อยู่ในรายการ "เฉยๆ" ตามเอกสาร:

JSR ที่ได้รับการโหวตให้เป็น "อยู่เฉยๆ" โดยคณะกรรมการบริหารหรือผู้ที่หมดอายุการใช้งานตามธรรมชาติ

ดูเหมือนว่าJSR 308 จะทำให้มันเป็น JDK 8 และแม้ว่า JSR จะไม่ได้กำหนด @NotNull แต่สิ่งที่แนบมาCheckers Frameworkนั้น ในขณะที่เขียนนี้ปลั๊กอิน Maven ไม่สามารถใช้งานได้เนื่องจากข้อผิดพลาดนี้: https://github.com/typetools/checker-framework/issues/183


2
ปัญหา showstopper สำหรับ maven ได้รับการแก้ไข ดังนั้นนี่ควรเป็นตัวเลือกอีกครั้ง
Marc von Renteln

ฉันใช้ FindBugs ผ่าน Maven ไม่มีอะไรทำโดย IDE ของฉันนี่เป็นการหลีกเลี่ยงคำอธิบายประกอบเฉพาะของ IDE คุณจะแนะนำอะไร
Christophe Roussy

@ChristopheRoussy คำถามของคุณเฉพาะ IDE โปรดเปิดคำถามแยกต่างหาก
Gili

15

แยกแยะระหว่างการวิเคราะห์แบบสแตติกและการวิเคราะห์แบบรันไทม์ ใช้การวิเคราะห์แบบสแตติกสำหรับเนื้อหาภายในและการวิเคราะห์แบบรันไทม์สำหรับขอบเขตสาธารณะของรหัสของคุณ

สำหรับสิ่งที่ไม่ควรเป็นโมฆะ:

  • การตรวจสอบรันไทม์: ใช้ "if (x == null) ... " (การพึ่งพาศูนย์) หรือ @ javax.validation.NotNull (พร้อมการตรวจสอบความถูกต้องของถั่ว) หรือ @ lombok.NonNull (ธรรมดาและเรียบง่าย) หรือ guavas Preconditions.checkNotNull (.. .)

    • ใช้ทางเลือกสำหรับประเภทการคืนเมธอด (เท่านั้น) Java8 หรือ Guava
  • ตรวจสอบคงที่: ใช้คำอธิบายประกอบ @NonNull

  • ใช้งานได้ตรงไหนใช้ @ ... หมายเหตุประกอบ NonnullByDefault ในระดับคลาสหรือแพ็กเกจ สร้างคำอธิบายประกอบเหล่านี้ด้วยตัวเอง (ตัวอย่างง่ายต่อการค้นหา)
    • มิฉะนั้นให้ใช้ @ ... CheckForNull เมื่อเมธอดส่งคืนเพื่อหลีกเลี่ยง NPE

สิ่งนี้ควรให้ผลลัพธ์ที่ดีที่สุด: คำเตือนใน IDE ข้อผิดพลาดโดย Findbugs และ checkerframework ข้อยกเว้นรันไทม์ที่มีความหมาย

อย่าคาดหวังว่าการตรวจสอบแบบสแตติกจะเป็นผู้ใหญ่การตั้งชื่อของพวกเขาไม่ได้มาตรฐานและมีห้องสมุดที่แตกต่างกัน คลาส JSR305 javax.annotations. * มีลักษณะเหมือนมาตรฐาน แต่ไม่ใช่และพวกเขาทำให้แพ็กเกจแยกด้วย Java9 +

คำอธิบายบันทึกย่อบางส่วน:

  • Findbugs / spotbugs / jsr305 หมายเหตุประกอบกับแพ็คเกจ javax.validation. * ปะทะกับโมดูลอื่น ๆ ใน Java9 + อาจละเมิดใบอนุญาต Oracle
  • คำอธิบายประกอบ Spotbugs ยังคงขึ้นอยู่กับคำอธิบายประกอบ jsr305 / findbugs ที่รวบรวม (ณ เวลาที่เขียนhttps://github.com/spotbugs/spotbugs/issues/421 )
  • jetbrains @NotNull ชื่อขัดแย้งกับ @ javax.validation.NotNull
  • คำอธิบายประกอบ jetbrains, eclipse หรือ checkersframework สำหรับการตรวจสอบแบบคงที่มีข้อได้เปรียบมากกว่า javax.annotations ที่พวกเขาไม่ได้ปะทะกับโมดูลอื่น ๆ ใน Java9 และสูงกว่า
  • @ javax.annotations.Nullable ไม่ได้หมายถึง Findbugs / Spotbugs สิ่งที่คุณ (หรือ IDE ของคุณ) คิดว่ามันหมายถึง Findbugs จะไม่สนใจมัน (สำหรับสมาชิก) เศร้า แต่จริง ( https://sourceforge.net/p/findbugs/bugs/1181 )
  • สำหรับการตรวจสอบแบบคงที่นอก IDE มีเครื่องมือฟรี 2 ตัว: Spotbugs (เดิมคือ Findbugs) และตัวตรวจสอบการทำงานของเฟรม
  • ไลบรารี Eclipse มี @NonNullByDefault, jsr305 เท่านั้นที่มี @ParametersAreNonnullByDefault สิ่งเหล่านี้เป็นเพียงเครื่องมืออำนวยความสะดวกที่ใช้คำอธิบายประกอบพื้นฐานกับทุกสิ่งในแพ็คเกจ (หรือคลาส) คุณสามารถสร้างของคุณเองได้อย่างง่ายดาย สามารถใช้กับแพ็คเกจได้ สิ่งนี้อาจขัดแย้งกับรหัสที่สร้างขึ้น (เช่น lombok)
  • ควรหลีกเลี่ยงการใช้ lombok เพื่อการพึ่งพาการส่งออกสำหรับไลบรารีที่คุณแชร์กับผู้อื่นยิ่งการพึ่งพาสกรรมกริยาน้อย
  • การใช้เฟรมเวิร์กการตรวจสอบความถูกต้องของ Bean นั้นมีประสิทธิภาพ แต่ต้องมีค่าใช้จ่ายสูงดังนั้นนั่นจึงเกินความจริงเพียงเพื่อหลีกเลี่ยงการตรวจสอบด้วยตนเอง
  • การใช้ตัวเลือกสำหรับฟิลด์และพารามิเตอร์เมธอดนั้นเป็นเรื่องที่ถกเถียงกันอยู่ (คุณสามารถค้นหาบทความเกี่ยวกับเรื่องนี้ได้อย่างง่ายดาย)
  • คำอธิบายประกอบ Android null เป็นส่วนหนึ่งของห้องสมุดสนับสนุน Android พวกเขามาพร้อมกับชั้นเรียนอื่น ๆ จำนวนมากและไม่เล่นอย่างสวยงามด้วยคำอธิบายประกอบ / เครื่องมืออื่น ๆ

ก่อน Java9 นี่คือคำแนะนำของฉัน:

// 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);
    }
}

โปรดทราบว่าไม่มีวิธีที่จะทำให้ Spotbugs เพิ่มการเตือนเมื่อมีการยกเลิกการอ้างอิงพารามิเตอร์เมธอด nullable (ในขณะที่เขียนรุ่น 3.1 ของ Spotbugs) บางทีตัวตรวจสอบเฟรมสามารถทำสิ่งนั้นได้

น่าเสียดายที่คำอธิบายประกอบเหล่านี้ไม่ได้แยกความแตกต่างระหว่างกรณีของวิธีการสาธารณะของห้องสมุดที่มีการใช้เว็บไซต์โดยพลการและวิธีการที่ไม่ใช่แบบสาธารณะซึ่งแต่ละเว็บไซต์สามารถทราบได้ ดังนั้นความหมายที่สองของ: "ระบุว่าเป็นโมฆะที่ไม่พึงประสงค์ แต่เตรียมความพร้อมสำหรับการถูกส่งผ่านไปอย่างไรก็ตาม" เป็นไปไม่ได้ในการประกาศเดียวดังนั้นตัวอย่างข้างต้นมีคำอธิบายประกอบที่แตกต่างกันสำหรับอินเตอร์เฟซและการใช้งาน

สำหรับกรณีที่วิธีการแยกส่วนต่อประสานนั้นไม่สามารถใช้งานได้จริง

        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);
        }

สิ่งนี้จะช่วยให้ลูกค้าไม่ผ่านการเป็นโมฆะ (การเขียนรหัสที่ถูกต้อง) ในขณะที่ส่งคืนข้อผิดพลาดที่เป็นประโยชน์หากพวกเขาทำ


ฉันพบคำตอบนี้เฉพาะตอนนี้ แต่ @tkruse คุณพบสิ่งนี้ได้ที่ไหน: "คำอธิบายประกอบ Eclipse jdt ไม่สามารถใช้ได้กับการส่งคืนเมธอดแบบสแตติกและกรณีอื่น ๆ "? (ส่วนแรกไม่เป็นความจริงส่วนที่สองค่อนข้างคลุมเครือ :))
Stephan Herrmann

@StephanHerrmann: ฉันจำไม่ได้ ฉันลบสัญลักษณ์แสดงหัวข้อ
tkruse

12

Eclipse มีคำอธิบายประกอบด้วยเช่นกัน

org.eclipse.jdt.annotation.NonNull

ดูที่http://wiki.eclipse.org/JDT_Core/Null_Analysisสำหรับรายละเอียด


ดูเหมือนว่าสิ่งนี้จะถูกรวมเข้ากับ Eclipse 3.8 (Juno) ซึ่งจะนำ Eclipse เข้ากับ IntelliJ ในเรื่องนี้ นอกจากนี้ควรอนุญาตให้คุณกำหนดค่าบันทึกย่อ Null ของคุณเอง (เช่น javax.annotation.Nonnull) และมีตัวเลือกให้ NotNull เป็นค่าเริ่มต้น
Motti Strom

11

เพียงแค่ชี้ให้เห็นว่า Java Validation API ( javax.validation.constraints.*) ไม่ได้มาพร้อมกับ@Nullableคำอธิบายประกอบซึ่งมีค่ามากในบริบทการวิเคราะห์แบบสแตติก มันสมเหตุสมผลสำหรับการตรวจสอบความถูกต้องรันไทม์ของถั่วเนื่องจากนี่เป็นค่าเริ่มต้นสำหรับฟิลด์ที่ไม่ใช่แบบดั้งเดิมใน Java (นั่นคือไม่มีอะไรให้ตรวจสอบ / บังคับใช้) สำหรับวัตถุประสงค์ที่ระบุไว้ว่าควรชั่งน้ำหนักต่อทางเลือก


7

น่าเสียดายที่JSR 308จะไม่เพิ่มค่ามากกว่าข้อเสนอแนะท้องถิ่นไม่ใช่ข้อเสนอแนะที่นี่

Java 8จะไม่มาพร้อมกับคำอธิบายประกอบเริ่มต้นเดียวหรือCheckerกรอบงานของตัวเอง คล้ายกับ Find-bugs หรือJSR 305JSR นี้ได้รับการดูแลไม่ดีโดยทีมวิชาการส่วนใหญ่

ไม่มีอำนาจเชิงพาณิชย์อยู่เบื้องหลังจึงJSR 308เปิดตัวEDR 3(Early Draft Review at JCP) ทันทีขณะนี้Java 8นี้คาดว่าจะจัดส่งได้ในเวลาน้อยกว่า 6 เดือน: -O คล้ายกับ310btw แต่สิ่งที่แตกต่างกัน308 Oracleคือการดูแลเรื่องนี้ออกไปจากผู้ก่อตั้งเพื่อลดอันตรายที่จะเกิดขึ้นกับแพลตฟอร์ม Java

ทุกโครงการผู้ขายและชั้นเรียนวิชาการเหมือนที่อยู่เบื้องหลัง Checker FrameworkและJSR 308จะสร้างคำอธิบายประกอบที่เป็นกรรมสิทธิ์ของตัวตรวจสอบ

การทำให้ซอร์สโค้ดไม่สามารถใช้ร่วมกันได้เป็นเวลาหลายปีจนกว่าจะพบการประนีประนอมที่เป็นที่นิยมและอาจถูกเพิ่มเข้าไปJava 9หรือ10หรือผ่านกรอบงานเช่นApache CommonsหรือGoogle Guava;-)


7

Android

คำตอบนี้เป็นเฉพาะ Android Android support-annotationsมีแพคเกจการสนับสนุนที่เรียกว่า แห่งนี้มีหลายสิบของAndroid เฉพาะคำอธิบายประกอบและยังให้คนทั่วไปเช่นNonNull, Nullableฯลฯ

ในการเพิ่มแพ็กเกจคำอธิบายประกอบให้เพิ่มการพึ่งพาต่อไปนี้ใน build.gradle ของคุณ:

compile 'com.android.support:support-annotations:23.1.1'

แล้วใช้:

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}

5

ในขณะที่รอสิ่งนี้จะถูกแยกออกเป็นอัปสตรีม (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 {}

สิ่งนี้เป็นที่ยอมรับกันว่าส่วนใหญ่ใช้สำหรับการตกแต่งหรือเพื่อพิสูจน์อนาคตเนื่องจากข้างต้นไม่ได้อยู่ในตัวของมันเองและเพิ่มการสนับสนุนใด ๆ สำหรับการวิเคราะห์แบบคงที่ของคำอธิบายประกอบเหล่านี้


4

หากคุณกำลังพัฒนาสำหรับ Android คุณค่อนข้างเชื่อมโยงกับ Eclipse (แก้ไข: ตอนที่เขียนไม่ใช่อีกต่อไป) ซึ่งมีบันทึกย่อของตัวเอง มันรวมอยู่ใน Eclipse 3.8+ (Juno) แต่ถูกปิดใช้งานโดยค่าเริ่มต้น

คุณสามารถเปิดใช้งานได้ที่การตั้งค่า> Java> คอมไพเลอร์> ข้อผิดพลาด / คำเตือน> การวิเคราะห์แบบ Null (ส่วนที่ยุบได้ที่ด้านล่าง)

ทำเครื่องหมาย "เปิดใช้งานการวิเคราะห์โมฆะตามหมายเหตุประกอบ"

http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usageมีคำแนะนำเกี่ยวกับการตั้งค่า อย่างไรก็ตามหากคุณมีโครงการภายนอกในพื้นที่ทำงานของคุณ (เช่น facebook SDK) พวกเขาอาจไม่ปฏิบัติตามคำแนะนำเหล่านั้นและคุณอาจไม่ต้องการแก้ไขด้วยการอัปเดต SDK แต่ละครั้ง ;-)

ฉันใช้:

  1. การเข้าถึงตัวชี้ Null: เกิดข้อผิดพลาด
  2. การละเมิดข้อกำหนดคุณสมบัติ null: ข้อผิดพลาด (เชื่อมโยงกับจุด # 1)
  3. การเข้าถึงตัวชี้ null ที่เป็นไปได้: คำเตือน (มิฉะนั้น facebook SDK จะมีคำเตือน)
  4. ความขัดแย้งระหว่างคำอธิบายประกอบแบบ null และการอนุมานแบบ null: คำเตือน (เชื่อมโยงกับจุดที่ 3)

4
เชื่อมโยงกับ Eclipse หรือไม่? ไม่จริง.
dcow

1
@DavidCowden IntelliJ IDEA พร้อมการสนับสนุนสำหรับ Android dev`ing ฉันคิดว่ามีเวลาพอสมควรก่อนที่ AndroidStudio จะได้รับการแนะนำ
Mārtiņš Briedis

@ MārtiņšBriedisใช่นั่นเป็นเรื่องจริง @chaqkeฉันคิดว่าคุณหมายถึง
dcow

เป็นที่น่าสังเกตว่า Android และ Intellij มีหมายเหตุประกอบแยกกันและมีแนวโน้มว่าจะยังคงเป็นเช่นนั้นจนกว่า java จะมีคำอธิบายประกอบอย่างเป็นทางการ นี่คือคำแนะนำสำหรับการใช้คำอธิบายประกอบของ eclipse กับ eclipse
chaqke

มันไม่เคยเชื่อมโยงกับ Eclipse คุณสามารถใช้ IDE ใด ๆ ที่คุณต้องการ
DennisK

4

หากคุณกำลังทำงานในโครงการขนาดใหญ่คุณอาจสร้างตัวเอง @Nullableและ / หรือ@NotNullหมายเหตุประกอบได้ดีกว่า

ตัวอย่างเช่น:

@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
@java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD,
                              java.lang.annotation.ElementType.METHOD,    
                              java.lang.annotation.ElementType.PARAMETER,
                              java.lang.annotation.ElementType.LOCAL_VARIABLE})
public @interface Nullable 
{
}

ถ้าคุณใช้ที่ถูกต้องนโยบายการเก็บรักษาแล้วคำอธิบายประกอบจะไม่สามารถใช้ได้ที่รันไทม์ จากมุมมองนั้นมันเป็นเพียงภายในสิ่ง

แม้ว่านี่จะไม่ใช่วิทยาศาสตร์ที่เข้มงวด แต่ฉันคิดว่ามันสมเหตุสมผลที่จะใช้คลาสภายในสำหรับมัน

  • มันเป็นสิ่งภายใน (ไม่มีผลกระทบการทำงานหรือทางเทคนิค)
  • ด้วยประเพณีมากมายมากมาย
  • IDE ของ IntelliJ รองรับการกำหนดเอง@Nullable/ @NotNullคำอธิบายประกอบ
  • เฟรมเวิร์กส่วนใหญ่ต้องการใช้เวอร์ชันภายในของตัวเองเช่นกัน

คำถามเพิ่มเติม (ดูความคิดเห็น):

วิธีกำหนดค่านี้ใน IntelliJ

คลิก "เจ้าหน้าที่ตำรวจ" ที่มุมล่างขวาของแถบสถานะ IntelliJ และคลิก "กำหนดค่าการตรวจสอบ" ในป๊อปอัพ ต่อไป ... กำหนดค่าคำอธิบายประกอบ


1
ฉันลองใช้คำแนะนำของคุณ แต่ideaไม่ได้บอกอะไรเลยเกี่ยวกับการvoid test(@NonNull String s) {}เรียกโดยtest(null);
user1244932

3
@ user1244932 คุณหมายถึง IntelliJ IDEA หรือเปล่า คุณสามารถกำหนดค่าคำอธิบายประกอบที่ไม่สามารถใช้ได้สำหรับการวิเคราะห์แบบคงที่ ฉันไม่รู้แน่ชัดว่าที่ไหน แต่ที่เดียวที่ให้คำจำกัดความคือ "ไฟล์> การตั้งค่า> Build, Execution, Deployment> Compiler" และมีปุ่ม "Configure annotations ... "
Adowrath

@ user1244932 ดูภาพหน้าจอหากคุณยังคงมองหาสิ่งนี้อยู่
bvdb

3

มีคำตอบมากเกินไปแล้วที่นี่ แต่ (ก) คือ 2019 และยังไม่มี "มาตรฐาน" Nullableและ (b) ไม่มีคำตอบอื่น ๆ อ้างอิง Kotlin

การอ้างอิงถึง Kotlin นั้นมีความสำคัญเนื่องจาก Kotlin นั้นสามารถใช้งานร่วมกับ Java ได้ 100% และมีคุณสมบัติหลักของ Null Safety เมื่อเรียกไลบรารี Java มันสามารถใช้ประโยชน์จากหมายเหตุประกอบเหล่านั้นเพื่อให้เครื่องมือ Kotlin ทราบว่า Java API สามารถยอมรับหรือส่งคืนได้หรือnullไม่

เท่าที่ฉันรู้Nullableแพคเกจเท่านั้นที่เข้ากันได้กับ Kotlin คือorg.jetbrains.annotationsและandroid.support.annotation(ตอนนี้androidx.annotation ) หลังเข้ากันได้กับ Android เท่านั้นจึงไม่สามารถใช้ในโครงการที่ไม่ใช่ Android JVM / Java / Kotlin อย่างไรก็ตามแพ็คเกจ JetBrains สามารถใช้งานได้ทุกที่

ดังนั้นหากคุณพัฒนาแพ็คเกจ Java ที่ควรทำงานใน Android และ Kotlin (และได้รับการสนับสนุนจาก Android Studio และ IntelliJ) ตัวเลือกที่ดีที่สุดของคุณน่าจะเป็นแพ็คเกจ JetBrains

Maven:

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations-java5</artifactId>
    <version>15.0</version>
</dependency>

Gradle:

implementation 'org.jetbrains:annotations-java5:15.0'

2
อืมสิ่งนี้พูดเป็นอย่างอื่น: kotlinlang.org/docs/reference/…
skagedal

3

มีวิธีอื่นในการทำเช่นนี้ใน Java 8 ฉันกำลังทำ 2 สิ่งเพื่อบรรลุสิ่งที่ฉันต้องการ:

  1. การทำให้เขตข้อมูล nullable ชัดเจนด้วยประเภทโดยการตัดเขตข้อมูล nullable ด้วย java.util.Optional
  2. ตรวจสอบว่าเขตข้อมูลที่ไม่สามารถลบล้างได้ทั้งหมดไม่เป็นโมฆะในเวลาการก่อสร้างด้วย 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 ของตัวเลือกที่ไม่ควรใช้ในการขัดแย้ง

ตัวเลือกอื่นเนื่องจากไม่แนะนำให้ใช้ตัวเลือกในอาร์กิวเมนต์เราต้องการตัวสร้าง 2 ตัว:

  //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();
      }

ฉันว่าคุณยังต้องใช้คำอธิบายประกอบ @NotNull สำหรับพารามิเตอร์ทางการทั้ง 4 ตัวเพื่อให้ผู้ตรวจสอบการวิเคราะห์ทราบความตั้งใจของคุณว่าไม่ควรมีค่าใด ยังไม่มีอะไรในภาษาจาวาที่บังคับใช้มัน คุณควรตรวจสอบคำอธิบายว่าไม่เป็นโมฆะหากคุณตั้งโปรแกรมป้องกันไว้
jaxzin

2
new Role(null,null,null,null);ฉันยังคงสามารถเขียนโค้ดนี้: ด้วยคำอธิบายประกอบ IDE และการวิเคราะห์แบบสแตติกของฉันจะเตือนว่า null ไม่สามารถส่งผ่านไปยังพารามิเตอร์เหล่านั้นได้ หากไม่มีมันฉันจะไม่พบจนกว่าฉันจะเรียกใช้รหัส นั่นคือมูลค่าของคำอธิบายประกอบ
jaxzin

2
ฉันยังอยู่ในสภาพแวดล้อมที่นักพัฒนาซอฟต์แวร์สามารถใช้ IDE หรือโปรแกรมแก้ไขข้อความที่ต้องการได้ จากนั้นเรายังรวม maven-pmd-plugin และ / หรือ SonarQube เข้าในกระบวนการสร้างเพื่อสนับสนุนและเน้นและแม้แต่เกตปัญหาเรื่องคุณภาพของโค้ดจะทำการผสานตัวอย่างเช่นเมื่อดึงคำขอ
jaxzin

2
ทางเลือกไม่ได้หมายถึงใช้เป็นอาร์กิวเมนต์เมธอดหรือฟิลด์ส่วนตัว ดูตัวอย่าง: stuartmarks.wordpress.com/2016/09/27/vjug24-session-on-optional
assylias

1
@ assylias ใช่ฉันพบว่าในภายหลังพวกเขาบอกว่ามันไม่แนะนำเพราะมันจะไม่ซื้ออะไรเราแน่นอนฉันสามารถเข้าใจเหตุผลของพวกเขา ในกรณีนี้ฉันใส่ที่นี่หนึ่งสามารถทำให้อาร์กิวเมนต์description ไม่เป็นโมฆะและรหัสลูกค้าสามารถผ่านสตริงที่ว่างเปล่า แต่ในหลายกรณีมันอาจจะมีประโยชน์ในการแยกแยะระหว่างและสตริงที่ว่างเปล่าและไม่มีค่า ขอบคุณสำหรับความคิดเห็นของคุณ ฉันจะอัปเดตคำตอบ
Mozart Brocchini

2

ตอนนี้ดวงอาทิตย์ไม่ได้เป็นของตัวเองเหรอ? นี่คืออะไร:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm

ดูเหมือนว่าจะได้รับการบรรจุด้วย Java ทุกเวอร์ชันที่ฉันใช้ภายในสองสามปีที่ผ่านมา

แก้ไข:ดังที่กล่าวไว้ในความคิดเห็นด้านล่างคุณอาจไม่ต้องการใช้สิ่งเหล่านี้ ในกรณีนั้นการลงคะแนนของฉันมีไว้สำหรับคำอธิบายประกอบ IntelliJ jetbrains!


10
ฉันไม่รู้ว่ามันคืออะไร แต่ชื่อแพคเกจควรเป็นเบาะแสขนาดใหญ่ที่ไม่ได้มีไว้สำหรับการใช้งานทั่วไป
สตีเฟ่นซี

3
มักจะละเว้นจากการใช้คลาสในเนมสเปซ com.sun เนื่องจากเป็นคลาสภายใน ไม่ได้มีไว้สำหรับการใช้งานโดยตรง และไม่มีการรับประกันความพร้อมใช้งานหรือพฤติกรรมในอนาคต หนึ่งจะต้องมีกรณีที่เป็นของแข็งจริงๆที่จะใช้สิ่งประดิษฐ์ com.sun โดยตรง
luis.espinal

รวมถึงบางสิ่งที่แสดงในรูปแบบ HTML ที่ไม่ดีเช่นนี้ (บน Java2s.com ไปยังด้านบนสุด) ควรให้ค่าสถานะสีแดงแก่คุณ :)
luis.espinal

2

หนึ่งในสิ่งที่ดีเกี่ยวกับ IntelliJ คือคุณไม่จำเป็นต้องใช้คำอธิบายประกอบ คุณสามารถเขียนของคุณเองหรือคุณสามารถใช้เครื่องมืออื่น ๆ ที่คุณชอบ คุณไม่ได้ จำกัด เพียงประเภทเดียว หากคุณใช้สองไลบรารีที่ใช้คำอธิบายประกอบ @NotNull ที่แตกต่างกันคุณสามารถบอก IntelliJ ให้ใช้ทั้งสองอย่างได้ ในการทำเช่นนี้ไปที่ "กำหนดค่าการตรวจสอบ" คลิกที่ "การตรวจสอบเงื่อนไขและข้อยกเว้น" อย่างต่อเนื่องและกดปุ่ม "กำหนดค่าการตรวจสอบ" ฉันใช้ตัวตรวจสอบ Nullness ทุกที่ที่ฉันทำได้ดังนั้นฉันจึงตั้งค่า IntelliJ ให้ใช้คำอธิบายประกอบเหล่านั้น แต่คุณสามารถทำให้มันทำงานกับเครื่องมืออื่น ๆ ที่คุณต้องการ (ฉันไม่มีความคิดเห็นเกี่ยวกับเครื่องมืออื่น ๆ เพราะฉันใช้การตรวจสอบของ IntelliJ มาหลายปีแล้วและฉันก็รักพวกเขา)


1

ตัวเลือกอื่นคือคำอธิบายประกอบที่มาพร้อมกับ ANTLR 4 ตามคำขอการดึง # 434สิ่งประดิษฐ์ที่มี@NotNullและ@Nullableคำอธิบายประกอบรวมถึงตัวประมวลผลคำอธิบายประกอบที่สร้างข้อผิดพลาดในการคอมไพล์เวลาและ / หรือคำเตือนในกรณีที่หนึ่งในแอตทริบิวต์เหล่านี้ ทั้งสองจะใช้กับรายการเดียวกันหรือหาก@Nullableใช้กับรายการที่มีประเภทดั้งเดิม) ตัวประมวลผลคำอธิบายประกอบให้ความมั่นใจเพิ่มเติมในระหว่างกระบวนการพัฒนาซอฟต์แวร์ว่าข้อมูลที่แอพพลิเคชั่นของคำอธิบายประกอบเหล่านี้มีความถูกต้องรวมถึงในกรณีของการสืบทอดวิธีการ


1

หากคุณกำลังสร้างแอปพลิเคชันของคุณโดยใช้ Spring Framework ฉันขอแนะนำให้ใช้การคอมjavax.validation.constraints.NotNullไพล์จากการตรวจสอบความถูกต้องของถั่วในการติดตามต่อไปนี้:

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>

javax.validation.constraints.NotNullประโยชน์หลักของคำอธิบายประกอบนี้คือฤดูใบไม้ผลิให้การสนับสนุนสำหรับทั้งพารามิเตอร์วิธีการและสาขาระดับกำกับด้วย สิ่งที่คุณต้องทำเพื่อเปิดใช้งานการสนับสนุนคือ:

  1. จัดหา api jar สำหรับการตรวจสอบถั่วและ jar ด้วยการใช้ตัวตรวจสอบความถูกต้องของคำอธิบายประกอบ jsr-303 / jsr-349 (ซึ่งมาพร้อมกับ Hibernate Validator 5.x dependency):

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.4.1.Final</version>
    </dependency>
  2. ให้ MethodValidationPostProcessor กับบริบทของสปริง

      @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
  3. ในที่สุดคุณจะใส่คำอธิบายประกอบชั้นเรียนของคุณด้วยสปริงorg.springframework.validation.annotation.Validatedและการตรวจสอบความถูกต้องจะได้รับการจัดการโดยสปริงโดยอัตโนมัติ

ตัวอย่าง:

@Service
@Validated
public class MyServiceImpl implements MyService {

  @Override
  public Something doSomething(@NotNull String myParameter) {
        // No need to do something like assert myParameter != null  
  }
}

เมื่อคุณพยายามเรียกวิธี doSomething และผ่าน null เป็นค่าพารามิเตอร์ฤดูใบไม้ผลิ (โดยวิธีการของ HibernateValidator) ConstraintViolationExceptionจะโยน ไม่จำเป็นสำหรับ manuall ทำงานที่นี่

นอกจากนี้คุณยังสามารถตรวจสอบค่าส่งคืน

ประโยชน์ที่สำคัญอีกอย่างหนึ่งของjavax.validation.constraints.NotNullการมอบกรอบการตรวจสอบความถูกต้องของถั่วคือในขณะนี้ยังคงมีการพัฒนาและมีการวางแผนคุณสมบัติใหม่สำหรับเวอร์ชัน 2.0 ใหม่

เกี่ยวกับ@Nullableอะไร ไม่มีอะไรที่เหมือนกับในการตรวจสอบความถูกต้องของถั่ว 1.1 ฉันอาจโต้เถียงได้ว่าหากคุณตัดสินใจที่จะใช้@NotNullมากกว่าทุกสิ่งที่ไม่ได้ใส่คำอธิบายประกอบ@NonNullอย่างมีประสิทธิภาพ "ไม่มีผล" ดังนั้น@Nullableคำอธิบายประกอบจึงไม่มีประโยชน์


1
โปรดอย่าใช้มัน มันถูกใช้สำหรับการตรวจสอบความถูกต้องรันไทม์ไม่ใช่การวิเคราะห์รหัสแบบคงที่ ดูjustsomejavaguy.blogspot.com/2011/08/…สำหรับรายละเอียด ที่มา: ลบคำตอบด้วยคะแนน 219 โดย @ luis.espinal
koppor

@ koppor: ฉันไม่เห็นด้วย หากนี่ไม่ได้มีไว้สำหรับการใช้งานเหตุใดสปริงจึงจัดการกับรันไทม์ เฟรมเวิร์กการตรวจสอบความถูกต้องของถั่วช่วยให้สามารถสร้างคำอธิบายประกอบได้อย่างหมดจดสำหรับการวิเคราะห์รันไทม์เนื่องจากอนุญาตให้เข้าถึงวัตถุบริบท
walkeros

0

Spring 5 มี @NonNullApi ที่ระดับแพ็คเกจ ดูเหมือนจะเป็นตัวเลือกที่สะดวกสำหรับโครงการที่มีการขึ้นต่อกันของสปริงแล้ว ฟิลด์พารามิเตอร์และค่าส่งคืนทั้งหมดเป็นค่าเริ่มต้นที่ @NonNull และ @Nullable สามารถนำไปใช้ในบางแห่งที่แตกต่างกัน

ไฟล์ package-info.java:

@org.springframework.lang.NonNullApi
package com.acme;

https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.