Kiểm tra các tham số được chú thích bằng @Nonnull cho null?


19

Chúng tôi đã bắt đầu sử dụng FindBugs và chú thích các tham số của chúng tôi @Nonnullmột cách thích hợp và nó hoạt động rất tốt để chỉ ra các lỗi sớm trong chu kỳ. Cho đến nay chúng tôi vẫn tiếp tục kiểm tra các đối số này để nullsử dụng Guava checkNotNull, nhưng tôi chỉ muốn kiểm tra nullcác cạnh - những nơi mà giá trị có thể đến mà không cần phải kiểm tra null, ví dụ: yêu cầu SOAP.

// service layer accessible from outside
public Person createPerson(@CheckForNull String name) {
    return new Person(Preconditions.checkNotNull(name));
}

...

// internal constructor accessed only by the service layer
public Person(@Nonnull String name) {
    this.name = Preconditions.checkNotNull(name);  // remove this check?
}

Tôi hiểu rằng @Nonnullkhông tự chặn nullgiá trị.

Tuy nhiên, do FindBugs sẽ chỉ ra bất cứ nơi nào một giá trị được chuyển từ một trường không được đánh dấu sang một trường được đánh dấu @Nonnull, chúng ta không thể phụ thuộc vào nó để bắt những trường hợp này (mà nó) mà không phải kiểm tra các giá trị này nullở mọi nơi mà chúng đi qua hệ thống? Tôi có ngây thơ muốn tin tưởng công cụ và tránh những kiểm tra dài dòng này không?

Điểm mấu chốt: Mặc dù có vẻ an toàn để loại bỏ nullkiểm tra thứ hai bên dưới, nhưng nó có phải là thực tế xấu?

Câu hỏi này có lẽ quá giống với câu hỏi Người ta nên kiểm tra null nếu anh ta không mong đợi null , nhưng tôi đang hỏi cụ thể liên quan đến @Nonnullchú thích.

Câu trả lời:


6

Nếu bạn không tin tưởng FindBug, nó có thể là một tùy chọn để sử dụng một xác nhận. Bằng cách này, bạn sẽ tránh được các sự cố được đề cập bởi Người dùng MSalters nhưng vẫn phải kiểm tra. Tất nhiên, cách tiếp cận này có thể không được áp dụng nếu cách tiếp cận không nhanh như vậy là không khả thi, tức là bạn phải nắm bắt bất kỳ ngoại lệ nào.

Và để trả lời thêm câu hỏi cho dù đó là thực hành xấu. Vâng, điều này là có thể tranh cãi nhưng tôi sẽ không nghĩ như vậy. Tôi coi chú thích FindBug này là một đặc điểm kỹ thuật nhẹ theo thiết kế theo nguyên tắc hợp đồng.

Trong thiết kế theo hợp đồng, bạn thiết lập một hợp đồng giữa một phương thức và người gọi nó. Hợp đồng bao gồm các điều kiện tiên quyết mà người gọi đồng ý thực hiện khi gọi phương thức và một điều kiện sau đó được thực hiện theo phương thức sau khi thực hiện nếu điều kiện tiên quyết của nó được thực hiện.

Một trong những lợi ích của phương pháp phát triển này là bạn có thể tránh được cái gọi là kiểu lập trình phòng thủ (trong đó bạn kiểm tra tất cả các giá trị tham số không hợp lệ một cách rõ ràng, v.v.). Thay vào đó, bạn có thể dựa vào hợp đồng và tránh kiểm tra dư thừa để tăng hiệu suất và khả năng đọc.

Hợp đồng có thể được sử dụng để kiểm tra xác nhận thời gian chạy theo nguyên tắc thất bại đầu tiên được đề cập ở trên mà bạn muốn chương trình của mình bị lỗi nếu hợp đồng bị phá vỡ, cung cấp cho bạn manh mối để xác định nguồn lỗi. (Điều kiện tiên quyết không thành công có nghĩa là người gọi đã làm gì đó sai, điều kiện hậu bị lỗi cho thấy lỗi thực thi của phương thức đã cho)

Hơn nữa, các hợp đồng có thể được sử dụng để phân tích tĩnh, cố gắng đưa ra kết luận về mã nguồn mà không thực sự chạy nó.

Chú thích @nonnull có thể được xem như một điều kiện tiên quyết được sử dụng để phân tích tĩnh bởi công cụ FindBugs. Nếu bạn thích một cách tiếp cận như kiểm tra xác nhận thời gian chạy, tức là chiến lược đầu tiên thất bại, bạn nên xem xét sử dụng các câu lệnh khẳng định như Java tích hợp. Hoặc có thể để thích ứng với chiến lược đặc tả kỹ thuật phức tạp hơn bằng cách sử dụng ngôn ngữ đặc tả giao diện hành vi, chẳng hạn như Ngôn ngữ mô hình hóa Java (JML).

JML là một phần mở rộng của Java trong đó đặc tả được nhúng trong các Nhận xét Java đặc biệt. Một lợi thế của phương pháp này là bạn có thể sử dụng thông số kỹ thuật tinh vi, thậm chí sử dụng phương pháp phát triển trong đó bạn chỉ dựa vào đặc điểm kỹ thuật thay vì chi tiết triển khai và sử dụng các công cụ khác nhau sử dụng thông số kỹ thuật, như các công cụ kiểm tra xác nhận thời gian chạy đã đề cập, tự động tạo ra các bài kiểm tra đơn vị hoặc tài liệu.

Nếu bạn chia sẻ quan điểm của tôi về việc @nonnull là một hợp đồng (nhẹ), thì sẽ không phổ biến nếu không thêm kiểm tra vì ý tưởng ban đầu đằng sau nguyên tắc này là tránh lập trình phòng thủ.


2
Đây chính xác là cách tôi đang sử dụng @Nonnull: như một đặc điểm kỹ thuật của hợp đồng. Tôi đã gỡ bỏ các kiểm tra phòng thủ đằng sau hợp đồng và cho đến nay không gặp khó khăn gì.
David Harkness

4

Chà, xem xét tại sao bạn không viết

this.name = Preconditions.checkNotNull(name);  // Might be necessary
that.name = Preconditions.checkNotNull(this.name);  // Who knows?

Lập trình không phải là ma thuật đen. Các biến không đột nhiên trở thành Null. Nếu bạn biết một biến không phải là Null, và bạn biết điều đó không thay đổi, sau đó làm không kiểm tra nó.

Nếu bạn kiểm tra nó, một số lập trình viên trong tương lai (có thể là bạn) sẽ dành nhiều thời gian để tìm hiểu lý do tại sao kiểm tra đó lại ở đó. Việc kiểm tra phải ở đó vì một lý do, sau tất cả, vậy bạn đang nhìn gì?


3
Các @Nonnullquy định hợp đồng mà người gọi không phải vượt qua nullđể các nhà xây dựng, và FindBugs sử dụng phân tích tĩnh để xác định vị trí các cuộc gọi có thể cho phép null--specifically cuộc gọi mà vượt qua giá trị không được đánh dấu @Nonnullbản thân. Nhưng một người gọi được tự do vượt qua nullvà bỏ qua cảnh báo từ FindBugs.
David Harkness

Lập trình lý tưởng không phải là ma thuật đen. Thật không may, hãy cẩn thận và ngạc nhiên, đặc biệt là khi làm việc với một số mã đồng thời ngoài đó ♬ ~ (ᐛ)
Tim Harper
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.