Sử dụng chú thích NotNull trong đối số phương thức


156

Tôi mới bắt đầu sử dụng @NotNullchú thích với Java 8 và nhận được một số kết quả không mong muốn.

Tôi có một phương pháp như thế này:

public List<Found> findStuff(@NotNull List<Searching> searchingList) {
    ... code here ...
}

Tôi đã viết một bài kiểm tra JUnit chuyển qua giá trị null cho đối số searchList. Tôi đã mong đợi một số loại lỗi xảy ra nhưng nó đã đi qua như thể chú thích không có ở đó. Đây có phải là hành vi dự kiến? Từ những gì tôi hiểu, điều này là để cho phép bạn bỏ qua việc viết mã kiểm tra null.

Một lời giải thích về chính xác những gì @NotNull được cho là sẽ được đánh giá cao.


29
@NotNullchỉ là một chú thích. Chú thích không làm gì cả. Họ cần một bộ xử lý chú thích vào thời gian biên dịch hoặc một cái gì đó xử lý nó khi chạy.
Sotirios Delimanolis 4/12/2015

Bạn có đang chạy mã bên trong một máy chủ ứng dụng (ví dụ: sử dụng Arquillian ) không?
jabu.10245

1
@SotiriosDelimanolis - Vậy thì vấn đề là gì, chỉ là một cảnh báo cho bất cứ ai gọi phương thức không vượt qua giá trị null? Trong trường hợp đó bạn vẫn cần mã xác thực con trỏ null.
DavidR

1
nhìn vào trình xác nhận ngủ đông
araluexis

@ jabu.10245 - Không sử dụng bất kỳ máy chủ ứng dụng nào.
DavidR

Câu trả lời:


183

@Nullable@NotNullkhông làm gì cả Chúng được cho là hoạt động như các công cụ Tài liệu.

Các @NullableChú nhắc nhở bạn về sự cần thiết để giới thiệu một kiểm tra NPE khi:

  1. Phương thức gọi có thể trả về null.
  2. Biến Dereferences (trường, biến cục bộ, tham số) có thể là null.

Các @NotNullchú giải là, trên thực tế, một hợp đồng rõ ràng tuyên bố sau đây:

  1. Một phương thức không nên trả về null.
  2. Một biến (như các trường, biến cục bộ và tham số) không thể giữ giá trị null.

Ví dụ: thay vì viết:

/**
 * @param aX should not be null
 */
public void setX(final Object aX ) {
    // some code
}

Bạn có thể dùng:

public void setX(@NotNull final Object aX ) {
    // some code
}

Ngoài ra, @NotNullthường được kiểm tra bởi ConstraintValidators (ví dụ: vào mùa xuân và ngủ đông).

Các @NotNullchú thích không làm bất cứ xác nhận ngày của riêng mình bởi vì định nghĩa chú thích không cung cấp bất kỳ ConstraintValidatortài liệu tham khảo loại.

Để biết thêm thông tin xem:

  1. Xác nhận đậu
  2. NotNull.java
  3. Constraint.java
  4. ConstraintValidator.java

3
Vì vậy, chỉ cần làm rõ phần 2 của phần NotNull, thực sự nó nên nói "không nên", không "không thể" vì nó không thể thực thi? Hoặc nếu nó có thể được thi hành trong thời gian chạy, bạn sẽ làm thế nào về điều đó?
DavidR

Đúng, đó là "không nên" ... việc thực hiện phương pháp sẽ thực thi hợp đồng.
justAntherUser ... 7/12/2015

1
Ngoài ra, trong Java 8, Optionalcó thể được sử dụng thay cho các @Nullgiá trị trả về và nạp chồng phương thức thay cho @Nullcác danh sách tham số: dolszewski.com/java/java-8-optional-use-case
Chad K

13
Tôi tin rằng sự nhầm lẫn xuất phát từ doc java của chú thích notnull: * The annotated element must not be {@code null}. * Accepts any type.và tôi nghĩ rằng phải từ nên được thay thế bằng nên nhưng một lần nữa nó phụ thuộc về cách bạn đọc nó. Chắc chắn một số làm rõ thêm sẽ tốt để có
Julian

@Julian Tôi nghĩ phải là thuật ngữ đúng vì đó là quy tắc, không phải là khuyến nghị. Nếu bạn sử dụng chú thích mà bạn không nên vượt qua nullnhưng nó sẽ được cho phép, bạn đang sử dụng chú thích sai. Thuật ngữ này không ngụ ý rằng nó được xác nhận. Tuy nhiên, một gợi ý rằng nó không được xác nhận sẽ không bị tổn thương. Nếu bạn muốn thêm xác nhận tự động, bạn có thể sử dụng một số công cụ bên ngoài. Ví dụ, IntelliJ IDE đã tích hợp hỗ trợ để thực hiện kiểm tra null.
JojOatXGME

27

Như đã đề cập ở trên @NotNullkhông có gì trên chính nó. Một cách tốt để sử dụng @NotNullsẽ là sử dụng nó vớiObjects.requireNonNull

public class Foo {
    private final Bar bar;

    public Foo(@NotNull Bar bar) {
        this.bar = Objects.requireNonNull(bar, "bar must not be null");
    }
}

6
Chỉ là một mẹo. Bạn cũng có thể viết các bài tập như vậy với một dòng:this.bar = Objects.requireNonNull(bar, "bar must not be null");
lolung

Cảm ơn mẹo @lolung - Hiện tại tôi đã cập nhật đoạn mã trên được cắt dựa trên nhận xét của bạn.
Bollywood


6

SO @NotNull chỉ là một thẻ ... Nếu bạn muốn xác thực nó, thì bạn phải sử dụng một cái gì đó như trình xác nhận hibernate jsr 303

ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
 Set<ConstraintViolation<List<Searching>> violations = validator.validate(searchingList);

Tôi đặt cái này ở đâu, vào đầu phương thức?
DavidR

vâng..tại đầu của phương thức ... đây chỉ là một trong những triển khai xác thực, cũng có thể có những người khác ...
Naruto

Đồng ý. Nhưng ý nghĩa này của những gì mã đó sẽ không thay đổi cho dù tôi có chú thích @NotNull trong đối số param hay không?
DavidR

Bây giờ bạn có tất cả các Vi phạm trong tập hợp, kiểm tra kích thước của nó, nếu nó lớn hơn 0 thì trả về từ phương thức.
Naruto


2

Tôi làm điều này để tạo chú thích và trình xác nhận hợp lệ của riêng tôi:

ValidCardType.java(chú thích để đặt trên các phương thức / trường)

@Constraint(validatedBy = {CardTypeValidator.class})
@Documented
@Target( { ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidCardType {
    String message() default "Incorrect card type, should be among: \"MasterCard\" | \"Visa\"";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Và, trình xác nhận để kích hoạt kiểm tra CardTypeValidator.java::

public class CardTypeValidator implements ConstraintValidator<ValidCardType, String> {
    private static final String[] ALL_CARD_TYPES = {"MasterCard", "Visa"};

    @Override
    public void initialize(ValidCardType status) {
    }
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return (Arrays.asList(ALL_CARD_TYPES).contains(value));
    }
}

Bạn có thể làm một cái gì đó rất giống để kiểm tra @NotNull.


0

Để kiểm tra xác thực phương thức của bạn trong một thử nghiệm, bạn phải bọc nó trong một phương thức @B Before.

@Before
public void setUp() {
    this.classAutowiredWithFindStuffMethod = MethodValidationProxyFactory.createProxy(this.classAutowiredWithFindStuffMethod);
}

Với Phương thứcValidationProxyFactory như:

import org.springframework.context.support.StaticApplicationContext;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

public class MethodValidationProxyFactory {

private static final StaticApplicationContext ctx = new StaticApplicationContext();

static {
    MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
    processor.afterPropertiesSet(); // init advisor
    ctx.getBeanFactory()
            .addBeanPostProcessor(processor);
}

@SuppressWarnings("unchecked")
public static <T> T createProxy(T instance) {

    return (T) ctx.getAutowireCapableBeanFactory()
            .applyBeanPostProcessorsAfterInitialization(instance, instance.getClass()
                    .getName());
}

}

Và sau đó, thêm bài kiểm tra của bạn:

@Test
public void findingNullStuff() {
 assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> this.classAutowiredWithFindStuffMethod.findStuff(null));

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