Tôi nên sử dụng chú thích Java @NotNull nào?


998

Tôi đang tìm cách làm cho mã của mình dễ đọc hơn cũng như sử dụng các công cụ như kiểm tra mã IDE và / hoặc phân tích mã tĩnh (FindBugs và Sonar) để tránh NullPulumExceptions. Nhiều công cụ dường như không tương thích với @NotNull/ @NonNull/ @Nonnullchú thích của nhau và liệt kê tất cả chúng trong mã của tôi sẽ rất tệ để đọc. Bất kỳ đề xuất nào trong số đó là 'tốt nhất'? Dưới đây là danh sách các chú thích tương đương tôi đã tìm thấy:

  • javax.validation.constraints.NotNull
    Tạo để xác thực thời gian chạy, không phân tích tĩnh.
    tài liệu

  • edu.umd.cs.findbugs.annotations.NonNull
    Được sử dụng bởi Findbugs phân tích tĩnh và do đó tài liệu Sonar (nay là Sonarqube )

  • javax.annotation.Nonnull
    Điều này cũng có thể hoạt động với Findbugs, nhưng JSR-305 không hoạt động. (Xem thêm: tình trạng của JSR 305 là gì? ) Nguồn

  • org.jetbrains.annotations.NotNull
    Được sử dụng bởi IntelliJ IDEA IDE để phân tích tĩnh.
    tài liệu

  • lombok.NonNull
    Được sử dụng để kiểm soát việc tạo mã trong Project Lombok .
    Chú thích giữ chỗ vì không có tiêu chuẩn.
    nguồn , tài liệu

  • android.support.annotation.NonNull
    Chú thích đánh dấu có sẵn trong Android, được cung cấp bởi tài liệu gói hỗ trợ chú thích

  • org.eclipse.jdt.annotation.NonNull
    Được sử dụng bởi Eclipse cho tài liệu phân tích mã tĩnh


203
apache nên phát minh ra một chú thích "chung" và một công cụ có thể chuyển đổi nó thành bất kỳ chú thích nào khác. giải pháp cho vấn đề quá nhiều tiêu chuẩn là phát minh ra một tiêu chuẩn mới.
chối cãi

6
@irreputable nếu apache phát minh ra một "phổ biến" mới, sẽ có 56 phiên bản của nó, chồng chéo với các dự án khác. Và, dù sao nó cũng không phải là tiêu chuẩn (tiêu chuẩn! = Phổ biến). Sử dụng tốt hơn bất cứ thứ gì thực sự chuẩn, javax ?. *. BTW, không có "quá nhiều tiêu chuẩn" trong các ví dụ đó, tôi chỉ thấy 1 hoặc 2.
ymajoros

6
javax.annotation.Nonnull không hoạt động với findbugs (chỉ thử nghiệm nó), đó là một lý do thuyết phục để tôi sử dụng nó.
Nicolas C

20
Nếu tôi chỉ đơn giản viết @NotNull, nó đề cập đến com.sun.istack.internal.NotNull. OMG ...
Thomas Weller

3
@MozartBrocchini - Tùy chọn rất hữu ích trong trường hợp bạn có thể đã sử dụng NullObjects trước đây. Mặc dù vậy, chúng không thực sự nhắm đến cùng một mục đích như một chú thích \ @NotNull và họ giới thiệu việc hủy kết nối tẻ nhạt.
Dave

Câu trả lời:


205

JSR 305 (có mục tiêu là tiêu chuẩn hóa @NonNull@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.annotationorg.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.

Để 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

7
Nhược điểm của javax.annotationnó là a) dựa trên một JSR đã chết, b) khó tìm thấy một vật phẩm chỉ cung cấp các chú thích và được duy trì. Một từ FindBugs không phải là: search.maven.org/...
robinst

18
Một điểm khác javax.annotationlà nó gây ra sự cố với Java 9 vì các mô-đun khác cũng cung cấp các lớp trong gói đó (jax-ws).
cướp

10
@kevinarpe: Dự án Findbugs đã chết và dự án kế nhiệm Spotbugs đang xóa các chú thích đó: github.com/spotbugs/spotbugs/pull/180
robinst

4
JSR 305 , đã được chuẩn hóa javax.annotation.NonNull, chưa bao giờ hoàn thành vì thông số kỹ thuật chính của nó đã đi AWOL. Nó không liên quan gì đến bất kỳ quyết định nào của Oracle.
Đánh dấu Reinhold

5
Một lý do khác để không sử dụng jsr305.jar là nó dường như vi phạm giấy phép nhị phân Java Java: github.com/google/guava/issues/2960
Flow

91

Tôi rất thích Khung kiểm tra , đây là một triển khai của các chú thích kiểu ( JSR-308 ) được sử dụng để triển khai các trình kiểm tra lỗi như trình kiểm tra null. Tôi chưa thực sự thử bất kỳ người nào khác để đưa ra bất kỳ so sánh nào, nhưng tôi rất vui với cách thực hiện này.

Tôi không liên kết với nhóm cung cấp phần mềm, nhưng tôi là một người hâm mộ.

Bốn điều tôi thích về hệ thống này:

  1. Nó có một công cụ kiểm tra khuyết tật về tính vô hiệu (@Nullable), nhưng cũng có những công cụ kiểm tra tính bất biếnthực tập (và những thứ khác). Tôi sử dụng cái thứ nhất (nullness) và tôi đang cố gắng sử dụng cái thứ hai (bất biến / IGJ). Tôi đang thử cái thứ ba, nhưng tôi không chắc chắn về việc sử dụng nó lâu dài. Tôi chưa bị thuyết phục về tính hữu dụng chung của các trình kiểm tra khác, nhưng thật tuyệt khi biết rằng chính khung này là một hệ thống để thực hiện một loạt các chú thích và trình kiểm tra bổ sung.

  2. Các thiết lập mặc định để kiểm tra nullness hoạt động tốt: Không rỗng ngoại trừ người dân địa phương (NNEL). Về cơ bản, điều này có nghĩa là theo mặc định, trình kiểm tra xử lý mọi nhịp (biến đối tượng, tham số phương thức, kiểu chung, v.v.) ngoại trừ các biến cục bộ như thể chúng có loại @NonNull theo mặc định. Theo tài liệu:

    Mặc định NNEL dẫn đến số lượng chú thích rõ ràng nhỏ nhất trong mã của bạn.

    Bạn có thể đặt mặc định khác cho một lớp hoặc cho một phương thức nếu NNEL không hoạt động cho bạn.

  3. Khung này cho phép bạn sử dụng mà không cần tạo phụ thuộc vào khung bằng cách đặt các chú thích của bạn trong một nhận xét: vd /*@Nullable*/. Điều này thật tuyệt vì bạn có thể chú thích và kiểm tra thư viện hoặc mã chia sẻ, nhưng vẫn có thể sử dụng thư viện / chia sẻ được mã hóa trong một dự án khác không sử dụng khung. Đây là một tính năng tốt đẹp. Tôi đã quen với việc sử dụng nó, mặc dù tôi có xu hướng kích hoạt Khung kiểm tra trên tất cả các dự án của tôi bây giờ.

  4. Khung này có một cách để chú thích các API mà bạn sử dụng chưa được chú thích cho tính không hợp lệ bằng cách sử dụng các tệp sơ khai.


3
Có vẻ tuyệt vời và tôi muốn sử dụng nó, nhưng không thể. Tại sao lại là GPL? Thay vào đó không phải là LGPL sao?
Burkhard

13
Theo Câu hỏi thường gặp : "Giấy phép MIT dễ dãi hơn áp dụng cho mã mà bạn có thể muốn đưa vào chương trình của riêng mình, chẳng hạn như các chú thích."
seanf

1
Các liên kết hiện đang bị hỏng. Nhưng +1 cho lời khuyên về việc sử dụng Khung kiểm tra.
Paul Wagland

1
Thật đáng tiếc khi các trình kiểm tra bất biến bị loại bỏ trong phiên bản mới nhất.
Franklin Yu

1
Khung kiểm tra cũng được đề xuất trong Hướng dẫn Java của Oracle .
Quazi Irfan

55

Tôi sử dụng IntelliJ, vì tôi chủ yếu quan tâm đến việc gắn cờ IntelliJ có thể tạo ra NPE. Tôi đồng ý rằng thật bực bội khi không có chú thích chuẩn trong JDK. Có nói về việc thêm nó, nó có thể biến nó thành Java 7. Trong trường hợp đó sẽ có thêm một lựa chọn nữa!


68
Cập nhật: IntelliJ hiện hỗ trợ tất cả các chú thích ở trên để làm nổi bật mã, vì vậy bạn không bị giới hạn ở các chú thích của IntelliJ nữa: blog.jetbrains.com/idea/2011/03/
Daniel Alexiuc

31
Và Juno Eclipse cũng vậy!
jFrenetic

5
javax.annotation.Nonnullđược chấp nhận rộng rãi hơn, phải không?
Martin

1
@DanielAlexiuc Nhưng thật không may, nó không sử dụng chúng để kiểm tra thời gian chạy của nó, vì vậy vẫn có lợi ích khi sử dụng JetBrains ...
Trejkaz

4
@Trejkaz Kể từ 2016.3, nó tạo ra các kiểm tra thời gian chạy cho tất cả những thứ đó.
Karol S

32

Theo danh sách các tính năng của Java 7, các chú thích loại JSR-308 được chuyển đến Java 8. Các chú thích JSR-305 thậm chí không được đề cập.

Có một chút thông tin về trạng thái của JSR-305 trong phần phụ lục của dự thảo JSR-308 mới nhất. Điều này bao gồm sự quan sát rằng các chú thích JSR-305 dường như bị bỏ rơi. Trang JSR-305 cũng hiển thị nó là "không hoạt động".

Trong khi đó, câu trả lời thực dụng là sử dụng các loại chú thích được hỗ trợ bởi các công cụ được sử dụng rộng rãi nhất ... và sẵn sàng thay đổi chúng nếu tình huống thay đổi.


Trong thực tế, JSR-308 không định nghĩa bất kỳ loại / lớp chú thích nào và có vẻ như chúng nghĩ rằng nó nằm ngoài phạm vi. (Và họ đã đúng, với sự tồn tại của JSR-305).

Tuy nhiên, nếu JSR-308 thực sự trông giống như biến nó thành Java 8, điều đó sẽ không làm tôi ngạc nhiên nếu sự quan tâm đến JSR-305 được hồi sinh. AFAIK, nhóm JSR-305 đã không chính thức từ bỏ công việc của họ. Họ chỉ im lặng trong hơn 2 năm.

Điều thú vị là Bill Pugh (lãnh đạo công nghệ cho JSR-305) là một trong những người đứng sau FindBugs.


4
@pst - lịch trình hiện tại dành cho Java 8 sẽ được phát hành chung vào tháng 9 năm 2013 - infoq.com/news/2012/04/jdk-8-milestone-release-dates
Stephen C

2
Điều đó đã trượt đến tháng 3 năm 2014 bây giờ - openjdk.java.net/projects/jdk8 . JSR 308 được bao gồm trong bản dựng M7 (xem trong "104 - Chú thích về các loại Java").
Stephen C

28

Đối với các dự án Android, bạn nên sử dụng android.support.annotation.NonNullandroid.support.annotation.Nullable. Những chú thích này và các chú thích cụ thể dành cho Android khác có sẵn trong Thư viện hỗ trợ .

Từ http://tools.android.com/tech-docs/support-annotations :

Bản thân thư viện hỗ trợ cũng đã được chú thích với các chú thích này, vì vậy với tư cách là người dùng thư viện hỗ trợ, Android Studio sẽ kiểm tra mã của bạn và gắn cờ các vấn đề tiềm ẩn dựa trên các chú thích này.


3
Nó sẽ hữu ích để cung cấp biện minh cho khuyến nghị đó.
mai

2
tools.android.com/tech-docs/support-annotations "Bản thân thư viện hỗ trợ cũng đã được chú thích với các chú thích này, vì vậy, khi là người dùng của thư viện hỗ trợ, Android Studio sẽ kiểm tra mã của bạn và gắn cờ các sự cố tiềm ẩn dựa trên các chú thích này . "
James Wald

3
BTW Android Studio cũng hỗ trợ jsr305 kèm theo javax.annotation.*chú thích
CAMOBAP

19

Nếu bất cứ ai chỉ tìm kiếm các lớp IntelliJ: bạn có thể lấy chúng từ kho lưu trữ maven với

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

Đây là một trong những nguyên nhân khiến Intellij đưa ra cảnh báo, vâng.
Nhấp vào Upvote

Phiên bản hiện tại (tính đến ngày 05/2017) là 15.0
BamaPookie

Quyền của bạn. Tôi đã cập nhật phiên bản. Ngay cả khi tôi đoán nó đã không thay đổi nhiều.
Bruno Eberhard

Hãy nhớ rằng các chú thích JetBrains không được giữ lại cho thời gian chạy, vì vậy, ví dụ như hỗ trợ Guice @Nullable không hoạt động với nó.
Peter Major

18

JSR305 và FindBugs được tác giả bởi cùng một người. Cả hai đều được bảo trì kém nhưng là tiêu chuẩn như nó được và được hỗ trợ bởi tất cả các IDE chính. Tin tốt là họ làm việc tốt.

Dưới đây là cách áp dụng @Nonnull cho tất cả các lớp, phương thức và trường theo mặc định. Xem https://stackoverflow.com/a/13319541/14731https://stackoverflow.com/a/9256595/14731

  1. Định nghĩa @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. Thêm chú thích vào mỗi gói: package-info.java

@NotNullByDefault
package com.example.foo;

CẬP NHẬT : Kể từ ngày 12 tháng 12 năm 2012, JSR 305 được liệt kê là "Không hoạt động". Theo tài liệu:

Một JSR đã được Ủy ban điều hành bầu chọn là "không hoạt động" hoặc một trong số đó đã đạt đến cuối tuổi thọ tự nhiên của nó.

Có vẻ như JSR 308 đang biến nó thành JDK 8 và mặc dù JSR không định nghĩa @NotNull, nhưng đi kèm Checkers Frameworkthì có. Tại thời điểm viết bài này, plugin Maven không sử dụng được do lỗi này: https://github.com/typetools/checker-framework/issues/183


2
Vấn đề showstopper cho maven đã được sửa. Vì vậy, đây nên là một lựa chọn một lần nữa.
Marc von Renteln

Tôi sử dụng FindBugs qua Maven, IDE của tôi không làm gì cả, điều này tránh các chú thích cụ thể của IDE, bạn muốn giới thiệu gì?
Barshe Roussy

@ChristopheRoussy Câu hỏi của bạn là dành riêng cho IDE. Vui lòng mở một câu hỏi riêng.
Gili

15

Phân biệt giữa phân tích tĩnh và phân tích thời gian chạy. Sử dụng phân tích tĩnh cho nội dung bên trong và phân tích thời gian chạy cho các ranh giới công khai của mã của bạn.

Đối với những thứ không nên null:

  • Kiểm tra thời gian chạy: Sử dụng "if (x == null) ..." (không phụ thuộc) hoặc @ javax.validation.NotNull (có xác thực bean) hoặc @ lombok.NonNull (đơn giản và đơn giản) hoặc guavas Preconditions.checkNotNull (.. .)

    • Sử dụng Tùy chọn cho các kiểu trả về phương thức (chỉ). Java8 hoặc ổi.
  • Kiểm tra tĩnh: Sử dụng chú thích @NonNull

  • Nếu nó phù hợp, hãy sử dụng các chú thích @ ... NonnullByDefault ở cấp độ lớp hoặc gói. Tự tạo các chú thích này (ví dụ rất dễ tìm).
    • Khác, sử dụng @ ... CheckForNull khi trả về phương thức để tránh NPE

Điều này sẽ cho kết quả tốt nhất: cảnh báo trong IDE, lỗi của Findbugs và checkerframework, ngoại lệ thời gian chạy có ý nghĩa.

Đừng hy vọng kiểm tra tĩnh sẽ thành thục, việc đặt tên của chúng không được chuẩn hóa và các thư viện và IDE khác nhau đối xử với chúng khác nhau, bỏ qua chúng. Các lớp javax.annotations của JSR305 trông giống như tiêu chuẩn, nhưng chúng không phải và chúng gây ra các gói phân tách với Java9 +.

Một số lưu ý giải thích:

  • Các chú thích Findbugs / spotbugs / jsr305 với gói javax.validation. * Xung đột với các mô-đun khác trong Java9 +, cũng có thể vi phạm giấy phép Oracle
  • Chú thích Spotbugs vẫn phụ thuộc vào chú thích jsr305 / findbugs tại compXLime (tại thời điểm viết https://github.com/spotbugs/spotbugs/issues/421 )
  • jetbrains @NotNull tên xung đột với @ javax.validation.NotNull.
  • Các chú thích máy bay phản lực, nhật thực hoặc chú thích kiểm tra khung hình để kiểm tra tĩnh có lợi thế hơn javax.annotations mà chúng không đụng độ với các mô-đun khác trong Java9 trở lên
  • @ javax.annotations.Nullable không có nghĩa là Findbugs / Spotbugs những gì bạn (hoặc IDE của bạn) nghĩ nó có nghĩa. Findbugs sẽ bỏ qua nó (trên các thành viên). Buồn, nhưng đúng ( https://sourceforge.net/p/findbugs/bugs/1181 )
  • Để kiểm tra tĩnh bên ngoài IDE, tồn tại 2 công cụ miễn phí: Spotbugs (trước đây là Findbugs) và checkersframework.
  • Thư viện Eclipse có @NonNullByDefault, jsr305 chỉ có @ParameterAreNonnullByDefault. Đó chỉ là các trình bao bọc tiện lợi áp dụng các chú thích cơ sở cho mọi thứ trong một gói (hoặc lớp), bạn có thể dễ dàng tạo riêng của mình. Điều này có thể được sử dụng trên gói. Điều này có thể mâu thuẫn với mã được tạo (ví dụ: lombok).
  • Nên tránh sử dụng lombok làm phụ thuộc xuất khẩu cho các thư viện mà bạn chia sẻ với người khác, càng ít phụ thuộc bắc cầu thì càng tốt
  • Sử dụng khung xác thực Bean rất mạnh, nhưng đòi hỏi chi phí cao, do đó, điều đó quá mức cần thiết để tránh kiểm tra null thủ công.
  • Sử dụng Tùy chọn cho các trường và tham số phương thức gây tranh cãi (bạn có thể tìm thấy các bài viết về nó một cách dễ dàng)
  • Các chú thích null của Android là một phần của thư viện hỗ trợ Android, chúng đi kèm với rất nhiều lớp khác và không chơi độc đáo với các chú thích / công cụ khác

Trước Java9, đây là khuyến nghị của tôi:

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

Lưu ý rằng không có cách nào để Spotbugs đưa ra cảnh báo khi tham số phương thức nullable bị hủy đăng ký (tại thời điểm viết, phiên bản 3.1 của Spotbugs). Có lẽ checkerframework có thể làm điều đó.

Đáng buồn thay, các chú thích này không phân biệt giữa các trường hợp của một phương thức công khai của một thư viện với các cuộc gọi tùy ý và các phương thức không công khai nơi mỗi cuộc gọi có thể được biết. Vì vậy, ý nghĩa kép của: "Chỉ ra rằng null là không mong muốn, tuy nhiên chuẩn bị cho null được thông qua" là không thể trong một khai báo, do đó ví dụ trên có các chú thích khác nhau cho giao diện và cách triển khai.

Đối với các trường hợp cách tiếp cận giao diện phân chia không thực tế, cách tiếp cận sau đây là một sự thỏa hiệp:

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

Điều này giúp khách hàng không vượt qua null (viết mã chính xác), trong khi trả lại các lỗi hữu ích nếu họ làm.


Bây giờ tôi chỉ tìm thấy câu trả lời này, nhưng @tkruse, bạn đã tìm thấy câu trả lời này ở đâu: "Chú thích jdt của Eclipse không áp dụng cho trả về phương thức tĩnh và một số trường hợp khác"? (phần thứ nhất không đúng, phần thứ hai khá mơ hồ :)).
Stephan Herrmann

@StephanHerrmann: Tôi không thể nhớ. Tôi gỡ bỏ điểm đạn.
tkruse

12

Eclipse cũng có chú thích riêng của nó.

org.eclipse.jdt.annotation.NonNull

Xem tại http://wiki.eclipse.org/JDT_Core/Null_Analysis để biết chi tiết.


Có vẻ như điều này sẽ được tích hợp từ Eclipse 3.8 (Juno), điều này sẽ đưa Eclipse phù hợp với IntelliJ về vấn đề này. Ngoài ra, nó sẽ cho phép bạn định cấu hình các chú thích Null của riêng bạn (ví dụ: javax.annotation.Nonnull) và có một tùy chọn để NotNull mặc định.
Motti Strom

11

Chỉ cần chỉ ra rằng API xác thực Java ( javax.validation.constraints.*) không đi kèm với @Nullablechú thích, rất có giá trị trong ngữ cảnh phân tích tĩnh. Điều này hợp lý cho việc xác thực bean thời gian chạy vì đây là mặc định cho bất kỳ trường không nguyên thủy nào trong Java (nghĩa là không có gì để xác thực / thi hành). Đối với các mục đích đã nêu rằng nên cân nhắc đối với các lựa chọn thay thế.


7

Thật không may, JSR 308sẽ không thêm nhiều giá trị hơn dự án Not Null cục bộ này tại đây

Java 8sẽ không đi kèm với một chú thích mặc định hoặc Checkerkhung riêng của nó . Tương tự như Tìm lỗi hoặcJSR 305 , JSR này được duy trì kém bởi một nhóm nhỏ hầu hết các nhóm học thuật.

Không có sức mạnh thương mại nào đằng sau nó, do đó JSR 308ra mắt EDR 3(Đánh giá Dự thảo sớm tại JCP) NGAY BÂY GIỜ, trong khi Java 8được cho là sẽ xuất xưởng trong vòng chưa đầy 6 tháng: -O Tương tự như 310btw. nhưng không thích308 Oracle đã chịu trách nhiệm về điều đó ngay từ những người sáng lập để giảm thiểu tác hại mà nó sẽ gây ra cho Nền tảng Java.

Mỗi dự án, nhà cung cấp và lớp học thuật giống như những người đứng sau Checker FrameworkJSR 308 sẽ tạo ra chú thích kiểm tra độc quyền của riêng mình.

Làm cho mã nguồn không tương thích trong nhiều năm tới, cho đến khi một vài thỏa hiệp phổ biến có thể được tìm thấy và có thể được thêm vào Java 9hoặc 10, hoặc thông qua các khung như Apache Commonshoặc Google Guava;-)


7

Android

Câu trả lời này là dành riêng cho Android. Android có gói hỗ trợ được gọi support-annotations. Điều này cung cấp hàng tá chú thích cụ thể của Android và cũng cung cấp những chú thích phổ biến như NonNull,Nullable v.v.

Để thêm gói chú thích hỗ trợ , hãy thêm phụ thuộc sau vào build.gradle của bạn:

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

và sau đó sử dụng:

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}

5

Trong khi chờ đợi điều này được sắp xếp ngược dòng (Java 8?), Bạn cũng có thể chỉ định nghĩa các chú thích cục bộ @NotNullvà dự án của riêng bạn @Nullable. Điều này cũng có thể hữu ích trong trường hợp bạn đang làm việc với Java SE, nơi javax.validation.constraints không có sẵn theo mặc định.

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 {}

Điều này sẽ được thừa nhận phần lớn là cho mục đích trang trí hoặc chứng minh trong tương lai, vì những điều trên rõ ràng không có trong và thêm bất kỳ sự hỗ trợ nào cho việc phân tích tĩnh các chú thích này.


4

Nếu bạn đang phát triển cho Android, bạn sẽ phần nào bị ràng buộc với Eclipse (chỉnh sửa: tại thời điểm viết, không còn nữa), có chú thích riêng. Nó được bao gồm trong Eclipse 3.8+ (Juno), nhưng bị tắt theo mặc định.

Bạn có thể kích hoạt nó tại Preferences> Java> Trình biên dịch> Lỗi / Cảnh báo> Phân tích Null (phần có thể thu gọn ở phía dưới).

Kiểm tra "Bật phân tích null dựa trên chú thích"

http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage có đề xuất về cài đặt. Tuy nhiên, nếu bạn có các dự án bên ngoài trong không gian làm việc của mình (như SDK facebook), chúng có thể không đáp ứng các đề xuất đó và có lẽ bạn không muốn sửa chúng với mỗi bản cập nhật SDK ;-)

Tôi sử dụng:

  1. Truy cập con trỏ Null: Lỗi
  2. Vi phạm đặc tả null: Lỗi (được liên kết với điểm # 1)
  3. Truy cập con trỏ null tiềm năng: Cảnh báo (nếu không, SDK SDK sẽ có cảnh báo)
  4. Xung đột giữa chú thích null và suy luận null: Cảnh báo (được liên kết với điểm # 3)

4
gắn liền với Eclipse? Không đúng.
dcow

1
@DavidCowden IntelliJ IDEA với sự hỗ trợ cho nhà phát triển Android, tôi nghĩ, đã có sẵn một thời gian trước khi AndroidStudio bị xâm phạm.
Mārtiņš Briedis

@ MārtiņšBriedis vâng, đó là sự thật. Tôi nghĩ bạn có ý đó @chaqke.
dcow

Điều đáng chú ý là Android và intellij có các chú thích riêng biệt và có khả năng sẽ vẫn như vậy cho đến khi java bao gồm các chú thích chính thức. đây là những hướng dẫn sử dụng chú thích của nhật thực với nhật thực.
chaqke

Nó chưa bao giờ được gắn với Eclipse. Bạn có thể sử dụng bất kỳ IDE nào bạn muốn.
DennisK

4

Nếu bạn đang làm việc trong một dự án lớn, bạn có thể tạo ra cái riêng của mình @Nullable và / hoặc@NotNull chú thích chú thích .

Ví dụ:

@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 
{
}

Nếu bạn sử dụng chính sách duy trì chính xác , thì các chú thích sẽ không có sẵn trong thời gian chạy . Từ quan điểm đó, nó chỉ là một nội bộ điều .

Mặc dù đây không phải là một khoa học nghiêm ngặt, tôi nghĩ sẽ hợp lý nhất khi sử dụng một lớp bên trong cho nó.

  • Đó là một điều nội bộ. (không có tác động chức năng hoặc kỹ thuật)
  • Với nhiều công dụng nhiều.
  • IDE giống như IntelliJ hỗ trợ tùy chỉnh @Nullable/ @NotNullchú thích.
  • Hầu hết các khung công tác cũng thích sử dụng phiên bản nội bộ của riêng họ.

Câu hỏi bổ sung (xem bình luận):

Làm cách nào để cấu hình cái này trong IntelliJ?

Nhấp vào "sĩ quan cảnh sát" ở góc dưới bên phải của thanh trạng thái IntelliJ. Và nhấp vào "Cấu hình kiểm tra" trong cửa sổ bật lên. Kế tiếp ... cấu hình chú thích


1
Tôi đã thử lời khuyên của bạn, nhưng ideakhông nói gì về việc void test(@NonNull String s) {}được gọi bởitest(null);
user1244932

3
@ user1244932 Ý bạn là IntelliJ IDEA? Bạn có thể định cấu hình các chú thích vô hiệu mà nó sử dụng để phân tích tĩnh. Tôi không biết chính xác nơi nào, nhưng một nơi để xác định chúng nằm trong "Tệp> Cài đặt> Xây dựng, Thực thi, Triển khai> Trình biên dịch" và ở đó có một nút "Định cấu hình chú thích ...".
Adowrath

@ user1244932 xem ảnh chụp màn hình nếu bạn vẫn đang tìm kiếm cái này.
bvdb

3

Đã có quá nhiều câu trả lời ở đây, nhưng (a) đó là năm 2019, và vẫn không có "tiêu chuẩn" Nullablevà (b) không có câu trả lời nào khác tham khảo Kotlin.

Tham chiếu đến Kotlin rất quan trọng, bởi vì Kotlin có thể tương tác 100% với Java và nó có tính năng Null Safety cốt lõi. Khi gọi các thư viện Java, nó có thể tận dụng các chú thích đó để cho các công cụ của Kotlin biết liệu API Java có thể chấp nhận hoặc trả về hay không null.

Theo tôi biết, các Nullablegói duy nhất tương thích với Kotlin là org.jetbrains.annotationsandroid.support.annotation(hiện tại androidx.annotation). Cái sau chỉ tương thích với Android nên không thể sử dụng nó trong các dự án JVM / Java / Kotlin không phải của Android. Tuy nhiên, gói JetBrains hoạt động ở mọi nơi.

Vì vậy, nếu bạn phát triển các gói Java cũng hoạt động trong Android và Kotlin (và được Android Studio và IntelliJ hỗ trợ), lựa chọn tốt nhất của bạn có lẽ là gói JetBrains.

Maven:

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

Học sinh lớp

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

2
Hmm, điều này nói khác: kotlinlang.org/docs/reference/ từ
skagedal

3

Có một cách khác để làm điều này trong Java 8. Tôi đang làm 2 việc để thực hiện những gì tôi cần:

  1. Làm cho các trường nullable rõ ràng với các loại bằng cách gói các trường nullable với java.util.Optional
  2. Kiểm tra xem tất cả các trường không null có phải là null tại thời điểm xây dựng với java.util.Objects.requireNonNull

Thí dụ:

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

Vì vậy, câu hỏi của tôi là, chúng ta thậm chí có cần chú thích khi sử dụng java 8 không?

Chỉnh sửa: Sau đó tôi phát hiện ra rằng một số người cho rằng một thực tiễn xấu được sử dụng Optionaltrong các đối số, có một cuộc thảo luận tốt với những ưu và nhược điểm ở đây Tại sao không nên sử dụng Tùy chọn của Java 8 trong các đối số

Tùy chọn thay thế cho rằng không nên sử dụng Tùy chọn trong các đối số, chúng tôi cần 2 hàm tạo:

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

Tôi muốn nói rằng bạn vẫn cần chú thích @NotNull cho cả 4 tham số chính thức để người kiểm tra phân tích tĩnh biết ý định của bạn rằng không nên có giá trị nào. Không có gì trong ngôn ngữ Java mà thực thi điều đó. Bạn cũng nên kiểm tra mô tả đó không phải là null nếu bạn đang lập trình phòng thủ.
jaxzin

2
Tôi vẫn có thể viết mã này : new Role(null,null,null,null);. Với các chú thích, IDE và phân tích tĩnh của tôi sẽ cảnh báo rằng null không thể được truyền vào các tham số đó. Không có nó tôi không tìm ra cho đến khi tôi chạy mã. Đó là giá trị của các chú thích.
jaxzin

2
Tôi cũng ở trong môi trường mà các nhà phát triển có thể sử dụng bất kỳ IDE hoặc trình soạn thảo văn bản nào họ thích, nó không loại trừ lẫn nhau. Sau đó, chúng tôi cũng tích hợp maven-pmd-plugin và / hoặc SonarQube vào quy trình xây dựng để khuyến khích và làm nổi bật, và thậm chí cổng, vấn đề chất lượng mã trước khi hợp nhất, ví dụ như đối với các yêu cầu kéo.
jaxzin

2
Tùy chọn không có nghĩa là được sử dụng làm đối số phương thức hoặc trường riêng. Xem ví dụ: stuartmark.wordpress.com/2016/09/27/vjug24-session-on-optional
assylias

1
@assylias vâng, tôi phát hiện ra rằng sau đó, họ nói rằng điều đó không được khuyến khích vì nó sẽ không mua cho chúng tôi bất cứ điều gì, tôi chắc chắn có thể hiểu lý trí của họ. Trong trường hợp này tôi đặt ở đây, người ta có thể làm cho đối số description không phải là null và mã máy khách có thể vượt qua một Chuỗi trống, nhưng trong nhiều trường hợp, có thể thuận tiện để phân biệt giữa và Chuỗi rỗng và không có giá trị. Cám ơn bạn đã góp ý. Tôi sẽ cập nhật câu trả lời.
Mozart Brocchini

2

Bây giờ không có mặt trời của riêng họ? Cái gì đây:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.i INTERNal.htmlm

Điều này dường như được đóng gói với tất cả các phiên bản Java tôi đã sử dụng trong vài năm qua.

Chỉnh sửa: Như đã đề cập trong các bình luận bên dưới, có lẽ bạn không muốn sử dụng chúng. Trong trường hợp đó, phiếu bầu của tôi là dành cho các chú thích máy bay phản lực IntelliJ!


10
Tôi không biết nó là gì, nhưng tên gói phải là LỚN LỚN mà nó KHÔNG dành cho sử dụng chung.
Stephen C

3
Người ta thường không sử dụng các lớp trong không gian tên com.sun vì chúng là nội bộ; không có nghĩa là để sử dụng trực tiếp; và không đảm bảo về tính khả dụng hoặc hành vi trong tương lai của họ. Người ta phải có một trường hợp thực sự vững chắc để trực tiếp sử dụng một tạo tác com.sun.
luis.espinal

cộng với một cái gì đó được hiển thị ở định dạng HTML kém như vậy (trên Java2s.com để tắt nó) sẽ cung cấp cho bạn một số cờ đỏ :)
luis.espinal

2

Một trong những điều hay về IntelliJ là bạn không cần sử dụng chú thích của họ. Bạn có thể tự viết, hoặc bạn có thể sử dụng những công cụ khác mà bạn thích. Bạn thậm chí không giới hạn trong một loại duy nhất. Nếu bạn đang sử dụng hai thư viện sử dụng các chú thích @NotNull khác nhau, bạn có thể yêu cầu IntelliJ sử dụng cả hai thư viện. Để thực hiện việc này, hãy chuyển đến "Cấu hình kiểm tra", nhấp vào kiểm tra "Điều kiện và ngoại lệ không đổi" và nhấn nút "Định cấu hình kiểm tra". Tôi sử dụng Trình kiểm tra Nullness bất cứ nơi nào tôi có thể, vì vậy tôi đã thiết lập IntelliJ để sử dụng các chú thích đó, nhưng bạn có thể làm cho nó hoạt động với bất kỳ công cụ nào bạn muốn. (Tôi không có ý kiến ​​gì về các công cụ khác vì tôi đã sử dụng các kiểm tra của IntelliJ trong nhiều năm và tôi yêu chúng.)


1

Một tùy chọn khác là các chú thích được cung cấp với ANTLR 4. Sau Yêu cầu kéo số 434 , tạo phẩm chứa @NotNull@Nullablechú thích bao gồm bộ xử lý chú thích tạo ra lỗi thời gian biên dịch và / hoặc cảnh báo trong trường hợp một trong các thuộc tính này bị sử dụng sai (ví dụ: cả hai đều được áp dụng cho cùng một mục hoặc nếu @Nullableđược áp dụng cho mục có kiểu nguyên thủy). Bộ xử lý chú thích cung cấp sự đảm bảo bổ sung trong quá trình phát triển phần mềm rằng thông tin được truyền tải bởi ứng dụng của các chú thích này là chính xác, kể cả trong các trường hợp kế thừa phương thức.


1

Nếu bạn đang xây dựng ứng dụng của mình bằng Spring Framework, tôi sẽ khuyên bạn nên sử dụng javax.validation.constraints.NotNullcomming từ Xác thực Đậu được đóng gói trong phần phụ thuộc sau:

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

Ưu điểm chính của chú thích này là Spring cung cấp hỗ trợ cho cả tham số phương thức và trường lớp được chú thích javax.validation.constraints.NotNull. Tất cả những gì bạn cần làm để kích hoạt hỗ trợ là:

  1. cung cấp bình api để xác thực đậu và bình với việc thực hiện trình xác nhận của các chú thích jsr-303 / jsr-349 (đi kèm với phụ thuộc Hibernate Validator 5.x):

    <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. cung cấp Phương thứcValidationPostProcessor cho bối cảnh của mùa xuân

      @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
  3. cuối cùng bạn chú thích các lớp của bạn với Spring org.springframework.validation.annotation.Validatedvà việc xác thực sẽ được Spring xử lý tự động.

Thí dụ:

@Service
@Validated
public class MyServiceImpl implements MyService {

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

Khi bạn thử gọi phương thức doS Something và truyền null làm giá trị tham số, spring (bằng phương tiện của HibernateValidator) sẽ ném ConstraintViolationException. Không cần làm việc ở đây.

Bạn cũng có thể xác nhận giá trị trả về.

Một lợi ích quan trọng khác của javax.validation.constraints.NotNullviệc xác nhận Khung xác thực Đậu là tại thời điểm này nó vẫn được phát triển và các tính năng mới được lên kế hoạch cho phiên bản 2.0 mới.

Thế còn @Nullable? Không có gì giống như vậy trong Xác thực Đậu 1.1. Chà, tôi có thể lập luận rằng nếu bạn quyết định sử dụng @NotNullhơn tất cả mọi thứ KHÔNG được chú thích @NonNullthì thực sự "vô hiệu", vì vậy @Nullablechú thích là vô dụng.


1
Xin vui lòng không sử dụng nó. Nó được sử dụng để xác nhận thời gian chạy, KHÔNG phân tích mã tĩnh. Xem jowersomejavaguy.blogspot.com/2011/08/ Khăn để biết chi tiết. Nguồn: XÓA câu trả lời với 219 phiếu bầu bởi @ luis.espinal.
koppor

@koppor: Tôi không đồng ý. Nếu điều này không nhằm mục đích sử dụng, tại sao Spring sẽ xử lý nó khi chạy. Ngoài ra khung xác thực Đậu cho phép tạo các chú thích hoàn toàn cho phân tích thời gian chạy, vì nó cho phép truy cập đối tượng Ngữ cảnh (hiện đang được chú thích / xác thực instancje) khi chạy.
walkeros

0

Spring 5 có @NonNullApi ở cấp gói. Đây có vẻ như là một lựa chọn thuận tiện cho một dự án đã có phụ thuộc Spring. Tất cả các trường, tham số và giá trị trả về mặc định cho @NonNull và @Nullable có thể được áp dụng ở một vài nơi khác nhau.

Gói tệp-info.java:

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

https://docs.spring.io/spring-data/commons/docs/civerse/reference/html/#repose khu.nullability.annotations

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.