Tôi có nên xác thực giá trị trả về của một cuộc gọi phương thức ngay cả khi tôi biết rằng phương thức đó không thể trả về đầu vào xấu?


30

Tôi tự hỏi liệu tôi có nên bảo vệ chống lại giá trị trả lại của một cuộc gọi phương thức hay không bằng cách xác nhận rằng chúng đáp ứng mong đợi của tôi ngay cả khi tôi biết rằng phương thức tôi đang gọi sẽ đáp ứng mong đợi đó.

ĐƯỢC

User getUser(Int id)
{
    User temp = new User(id);
    temp.setName("John");

    return temp;
}

TÔI NÊN LÀM

void myMethod()
{
    User user = getUser(1234);
    System.out.println(user.getName());
}

HOẶC LÀ

void myMethod()
{
    User user = getUser(1234);

    // Validating
    Preconditions.checkNotNull(user, "User can not be null.");
    Preconditions.checkNotNull(user.getName(), "User's name can not be null.");

    System.out.println(user.getName());
}

Tôi đang hỏi điều này ở cấp độ khái niệm. Nếu tôi biết hoạt động bên trong của phương thức tôi đang gọi. Hoặc bởi vì tôi đã viết nó hoặc tôi đã kiểm tra nó. Và logic của các giá trị có thể nó trả về đáp ứng các điều kiện tiên quyết của tôi. Là "tốt hơn" hay "phù hợp hơn" để bỏ qua xác nhận, hoặc tôi vẫn nên bảo vệ chống lại các giá trị sai trước khi tiếp tục với phương pháp tôi hiện đang thực hiện ngay cả khi nó luôn luôn vượt qua.


Kết luận của tôi từ tất cả các câu trả lời (cứ tự nhiên đến với bạn):

Khẳng định khi nào
  • Phương pháp này đã cho thấy hoạt động sai trong quá khứ
  • Phương pháp này là từ một nguồn không đáng tin cậy
  • Phương thức này được sử dụng từ những nơi khác và không nói rõ điều kiện hậu
Không khẳng định khi nào:
  • Phương pháp này gần với phương thức của bạn (xem câu trả lời được chọn để biết chi tiết)
  • Phương thức xác định rõ ràng hợp đồng của nó với một cái gì đó như tài liệu phù hợp, loại an toàn, kiểm tra đơn vị hoặc kiểm tra sau điều kiện
  • Hiệu suất là rất quan trọng (trong trường hợp đó, một chế độ gỡ lỗi khẳng định có thể hoạt động như một phương pháp lai)

1
Nhằm mục đích bảo hiểm mã 100% đó!
Jared Burrows

9
Tại sao bạn chỉ tập trung vào một vấn đề ( Null)? Có lẽ vấn đề không kém nếu tên đó ""(không phải là null mà là chuỗi rỗng) hoặc "N/A". Hoặc bạn có thể tin tưởng vào kết quả, hoặc bạn phải bị hoang tưởng một cách thích hợp.
MSalters

3
Trong cơ sở mã của chúng tôi, chúng tôi có một sơ đồ đặt tên: getFoo () hứa sẽ không trả về null và getFoo IfPftime () có thể trả về null.
pjc50

Trường hợp giả định của bạn về sự tỉnh táo mã đến từ đâu? Bạn có cho rằng giá trị sẽ luôn là không vì nó được xác thực khi nhập hoặc do cấu trúc mà giá trị được truy xuất? Và, quan trọng hơn, bạn đang thử nghiệm mọi tình huống cạnh có thể xảy ra? Bao gồm khả năng của kịch bản độc hại?
Zibbobz

Câu trả lời:


42

Điều đó phụ thuộc vào khả năng getUser và myMethod thay đổi như thế nào và quan trọng hơn là khả năng thay đổi độc lập với nhau như thế nào .

Nếu bạn bằng cách nào đó biết chắc chắn rằng getUser sẽ không bao giờ thay đổi trong tương lai, thì đúng là lãng phí thời gian để xác nhận nó, cũng như lãng phí thời gian để xác nhận igiá trị là 3 ngay sau một i = 3;tuyên bố. Trong thực tế, bạn không biết điều đó. Nhưng có một số điều bạn biết:

  • Hai chức năng này có "sống chung" không? Nói cách khác, họ có cùng một người duy trì chúng không, chúng có phải là một phần của cùng một tệp không, và do đó chúng có khả năng ở lại "đồng bộ" với nhau không? Trong trường hợp này, có thể quá mức cần thiết để thêm kiểm tra xác thực, vì điều đó chỉ có nghĩa là nhiều mã phải thay đổi (và có khả năng sinh ra lỗi) mỗi khi hai hàm thay đổi hoặc được tái cấu trúc thành một số hàm khác nhau.

  • Hàm getUser có phải là một phần của API tài liệu với một hợp đồng cụ thể không và myMethod chỉ là một ứng dụng khách của API đã nói trong một cơ sở mã khác? Nếu vậy, bạn có thể đọc tài liệu đó để tìm hiểu xem bạn nên xác thực các giá trị trả về (hoặc xác thực trước các tham số đầu vào!) Hoặc nếu nó thực sự an toàn để mù quáng đi theo con đường hạnh phúc. Nếu tài liệu không làm rõ điều này, hãy yêu cầu người bảo trì sửa nó.

  • Cuối cùng, nếu chức năng đặc biệt này đột nhiên và bất ngờ thay đổi hành vi của nó trong quá khứ, theo cách phá vỡ mã của bạn, bạn có quyền hoang tưởng về nó. Lỗi có xu hướng co cụm.

Lưu ý rằng tất cả các điều trên áp dụng ngay cả khi bạn là tác giả ban đầu của cả hai chức năng. Chúng tôi không biết liệu hai chức năng này có được dự kiến ​​sẽ "sống cùng nhau" trong suốt quãng đời còn lại hay không, nếu chúng sẽ dần dần tách ra thành các mô-đun riêng biệt, hoặc nếu bạn bằng cách nào đó tự bắn vào chân mình bằng một lỗi cũ phiên bản của getUser. Nhưng bạn có thể có thể đoán khá tốt.


2
Ngoài ra: Nếu bạn thay đổi getUsersau này, để nó có thể trả về null, thì kiểm tra rõ ràng có cung cấp cho bạn thông tin bạn không thể nhận được từ "NullPulumException" và số dòng không?
dùng253751

Dường như có hai điều bạn có thể xác nhận: (1) Phương thức này hoạt động đúng, như trong, nó không có lỗi. (2) Phương pháp đó tôn trọng hợp đồng của bạn. Tôi có thể thấy việc xác nhận số 1 là quá mức cần thiết. Bạn nên có các bài kiểm tra làm # 1 thay thế. Đó là lý do tại sao tôi sẽ không xác nhận i = 3;. Vì vậy, câu hỏi của tôi liên quan đến # 2. Tôi thích câu trả lời của bạn cho điều đó, nhưng đồng thời, đó là cách sử dụng câu trả lời phán xét của bạn. Bạn có thấy bất kỳ vấn đề nào khác phát sinh từ việc xác nhận rõ ràng các hợp đồng của mình sau đó lãng phí một chút thời gian để viết khẳng định không?
Didier A.

"Vấn đề" duy nhất khác là nếu cách giải thích hợp đồng của bạn sai hoặc trở nên sai, thì bạn phải thay đổi tất cả xác nhận. Nhưng điều đó áp dụng cho tất cả các mã khác quá.
Ixrec

1
Không thể đi ngược lại đám đông. Câu trả lời này chắc chắn là chính xác nhất trong việc bao quát chủ đề của câu hỏi của tôi. Tôi muốn thêm rằng từ việc đọc tất cả các câu trả lời, đặc biệt là @MikeNakis, bây giờ tôi nghĩ bạn nên khẳng định các điều kiện trước của mình, ít nhất là trong chế độ gỡ lỗi, khi bạn có một trong hai điểm cuối của Ixrec. Nếu bạn phải đối mặt với điểm đạn đầu tiên, thì có lẽ nó quá mức cần thiết để khẳng định điều kiện tiên quyết của bạn. Cuối cùng, được đưa ra một hợp đồng rõ ràng, như tài liệu phù hợp, loại an toàn, kiểm tra đơn vị hoặc kiểm tra sau điều kiện, bạn không nên khẳng định các điều kiện tiên quyết của mình, điều đó sẽ là quá mức cần thiết.
Didier A.

22

Câu trả lời của Ixrec là tốt, nhưng tôi sẽ có một cách tiếp cận khác bởi vì tôi tin rằng nó đáng để xem xét. Với mục đích của cuộc thảo luận này, tôi sẽ nói về các xác nhận, vì đó là tên mà Preconditions.checkNotNull()theo truyền thống của bạn đã được biết đến.

Điều tôi muốn đề xuất là các lập trình viên thường đánh giá quá cao mức độ mà họ chắc chắn rằng một cái gì đó sẽ hành xử theo một cách nhất định và đánh giá thấp hậu quả của việc nó không hành xử theo cách đó. Ngoài ra, các lập trình viên thường không nhận ra sức mạnh của các xác nhận là tài liệu. Sau đó, theo kinh nghiệm của tôi, các lập trình viên khẳng định mọi thứ ít thường xuyên hơn mức họ nên làm.

Phương châm của tôi là:

Câu hỏi bạn nên luôn tự hỏi mình là "tôi có nên khẳng định điều này không?" nhưng "có gì tôi quên khẳng định không?"

Đương nhiên, nếu bạn hoàn toàn chắc chắn rằng một cái gì đó hành xử theo một cách nhất định, bạn sẽ không thể khẳng định rằng thực tế nó đã hành xử theo cách đó, và đó là phần hợp lý nhất. Thật sự không thể viết phần mềm nếu bạn không thể tin tưởng bất cứ điều gì.

Nhưng có những ngoại lệ ngay cả với quy tắc này. Thật kỳ lạ, để lấy ví dụ của Ixrec, tồn tại một loại tình huống mà nó hoàn toàn mong muốn tuân theo int i = 3;với một khẳng định ithực sự nằm trong một phạm vi nhất định. Đây là tình huống có ithể bị thay đổi bởi một người đang thử nhiều kịch bản giả định khác nhau và mã theo sau icó giá trị trong một phạm vi nhất định và không rõ ràng ngay lập tức bằng cách xem nhanh mã sau đây phạm vi chấp nhận được là. Vì vậy, int i = 3; assert i >= 0 && i < 5;thoạt đầu có vẻ vô lý, nhưng nếu bạn nghĩ về nó, nó sẽ cho bạn biết rằng bạn có thể chơi cùng i, và nó cũng cho bạn biết phạm vi mà bạn phải ở lại. Một khẳng định là loại tài liệu tốt nhất, bởi vìnó được thi hành bởi máy , vì vậy nó là một sự đảm bảo hoàn hảo và nó được tái cấu trúc cùng với mã , vì vậy nó vẫn luôn luôn thích hợp.

getUser(int id)Ví dụ của bạn không phải là một khái niệm rất xa của assign-constant-and-assert-in-rangeví dụ. Theo định nghĩa, bạn thấy lỗi xảy ra khi mọi thứ thể hiện hành vi khác với hành vi mà chúng ta mong đợi. Đúng, chúng tôi không thể khẳng định mọi thứ, vì vậy đôi khi sẽ có một số gỡ lỗi. Nhưng có một thực tế được xác định rõ ràng trong ngành là chúng ta càng nhanh chóng bắt lỗi thì càng ít chi phí. Các câu hỏi bạn nên hỏi không chỉ là chắc chắn bạn getUser()sẽ không bao giờ trả về null, (và không bao giờ trả lại người dùng có tên null), mà còn, những điều tồi tệ nào sẽ xảy ra với phần còn lại của mã nếu nó xảy ra thực tế một ngày nào đó trả lại một cái gì đó bất ngờ, và thật dễ dàng bằng cách nhanh chóng nhìn vào phần còn lại của mã để biết chính xác những gì được mong đợi getUser().

Nếu hành vi không mong muốn sẽ khiến cơ sở dữ liệu của bạn bị hỏng, thì có lẽ bạn nên khẳng định ngay cả khi bạn chắc chắn 101% sẽ không xảy ra. Nếu một nulltên người dùng sẽ gây ra một số lỗi khó hiểu khó hiểu về hàng ngàn dòng xuống và hàng tỷ chu kỳ đồng hồ sau đó, thì có lẽ tốt nhất là thất bại càng sớm càng tốt.

Vì vậy, mặc dù tôi không đồng ý với câu trả lời của Ixrec, tôi sẽ đề nghị bạn nghiêm túc xem xét thực tế rằng các xác nhận không có gì, vì vậy thực sự không có gì để mất, chỉ có thể đạt được, bằng cách sử dụng chúng một cách tự do.


2
Vâng. Khẳng định đi. Tôi đến đây để đưa ra ít nhiều câu trả lời này. ++
RubberDuck

2
@SteveJessop Tôi sẽ sửa nó thành ... && sureness < 1).
Mike Nakis

2
@MikeNakis: đó luôn là cơn ác mộng khi viết bài kiểm tra đơn vị, giá trị trả về được giao diện cho phép nhưng không thể thực sự tạo ra từ bất kỳ đầu vào nào ;-) Dù sao, khi bạn chắc chắn 101% bạn đã đúng thì bạn chắc chắn sai !
Steve Jessop

2
+1 để chỉ ra những điều tôi hoàn toàn quên đề cập đến trong câu trả lời của mình.
Ixrec

1
@DavidZ Điều đó đúng, câu hỏi của tôi giả sử xác thực thời gian chạy. Nhưng nói rằng bạn không tin tưởng vào phương pháp gỡ lỗi và tin tưởng vào prod là một quan điểm có thể tốt về chủ đề này. Vì vậy, một phong cách C khẳng định có thể là một cách tốt để đối phó với tình huống này.
Didier A.

8

Một không xác định.

Một người gọi không nên kiểm tra xem chức năng mà nó đang gọi có tôn trọng hợp đồng của nó không. Lý do rất đơn giản: có khả năng rất nhiều người gọi và nó không thực tế và thậm chí còn sai theo quan điểm khái niệm cho mỗi và mọi người gọi để sao chép logic để kiểm tra kết quả của các chức năng khác.

Nếu bất kỳ kiểm tra nào được thực hiện, mỗi chức năng nên kiểm tra các điều kiện hậu của chính nó. Các điều kiện hậu kỳ giúp bạn tự tin rằng bạn đã thực hiện chức năng một cách chính xác và người dùng sẽ có thể dựa vào hợp đồng của chức năng của bạn.

Nếu một chức năng nhất định không bao giờ trả về null, thì điều này sẽ được ghi lại và trở thành một phần của hợp đồng của chức năng đó. Đây là điểm của các hợp đồng này: cung cấp cho người dùng một số bất biến mà họ có thể dựa vào để họ đối mặt với ít trở ngại hơn khi viết các chức năng của riêng họ.


Tôi đồng ý với tình cảm chung, nhưng có những trường hợp chắc chắn có ý nghĩa để xác nhận giá trị trả về. Ví dụ: nếu bạn gọi một Dịch vụ web bên ngoài, đôi khi bạn muốn xác thực ít nhất định dạng của câu trả lời (xsd, v.v.)
AK_

Có vẻ như bạn đang ủng hộ kiểu Thiết kế theo Hợp đồng so với kiểu Lập trình phòng thủ. Tôi nghĩ rằng đây là một câu trả lời tuyệt vời. Nếu phương pháp có một hợp đồng nghiêm ngặt, tôi có thể tin tưởng nó. Trong trường hợp của tôi thì không, nhưng tôi có thể thay đổi nó để làm như vậy. Nói rằng tôi không thể mặc dù? Bạn có cho rằng tôi nên tin tưởng vào việc thực hiện? Ngay cả khi nó không tuyên bố rõ ràng trong tài liệu của nó rằng nó không trả về null hoặc thực sự có kiểm tra hậu điều kiện?
Didier A.

Theo tôi, bạn nên sử dụng khả năng phán đoán tốt nhất và cân nhắc các khía cạnh khác nhau như mức độ bạn tin tưởng tác giả để làm đúng, khả năng thay đổi giao diện của chức năng và mức độ hạn chế về thời gian của bạn. Điều đó đang được nói, hầu hết thời gian, tác giả của một chức năng có một ý tưởng khá rõ ràng về hợp đồng của chức năng đó là gì, ngay cả khi anh ta không ghi chép lại. Vì điều này, tôi nói trước tiên bạn nên tin tưởng các tác giả làm điều đúng đắn và chỉ trở nên phòng thủ khi bạn biết rằng chức năng này không được viết tốt.
Paul

Tôi thấy rằng trước tiên tin tưởng người khác làm điều đúng sẽ giúp tôi hoàn thành công việc nhanh hơn. Điều đó đang được nói, loại ứng dụng tôi viết rất dễ khắc phục khi xảy ra sự cố. Ai đó làm việc với phần mềm quan trọng hơn về an toàn có thể nghĩ rằng tôi quá khoan dung và thích cách tiếp cận phòng thủ hơn.
Paul

5

Nếu null là giá trị trả về hợp lệ của phương thức getUser, thì mã của bạn sẽ xử lý điều đó với If, không phải là Ngoại lệ - đó không phải là trường hợp ngoại lệ.

Nếu null không phải là giá trị trả về hợp lệ của phương thức getUser, thì có một lỗi trong getUser - phương thức getUser sẽ đưa ra một ngoại lệ hoặc nếu không thì sẽ được sửa.

Nếu phương thức getUser là một phần của thư viện bên ngoài hoặc nếu không thì không thể thay đổi và bạn muốn ném ngoại lệ trong trường hợp trả về null, hãy bọc lớp và phương thức để thực hiện kiểm tra và ném ngoại lệ sao cho mọi trường hợp của lệnh gọi getUser phù hợp với mã của bạn.


Null không phải là giá trị trả về hợp lệ của getUser. Bằng cách kiểm tra getUser, tôi thấy rằng việc triển khai sẽ không bao giờ trả về null. Câu hỏi của tôi là, tôi có nên tin tưởng vào sự kiểm tra của mình và không có kiểm tra trong phương pháp của tôi hay tôi nên nghi ngờ về việc kiểm tra của mình và vẫn có một kiểm tra. Cũng có thể phương thức thay đổi trong tương lai, phá vỡ kỳ vọng của tôi về việc không trả về null.
Didier A.

Và nếu getUser hoặc user.getName thay đổi để ném ngoại lệ thì sao? Bạn nên có một kiểm tra, nhưng không phải là một phần của phương pháp sử dụng Người dùng. Bao bọc phương thức getUser - và thậm chí cả lớp Người dùng - để thực thi các hợp đồng của bạn, nếu bạn lo lắng về những thay đổi trong tương lai đối với việc phá vỡ mã getUser. Đồng thời tạo các bài kiểm tra đơn vị để kiểm tra các giả định của bạn về hành vi của lớp.
MatthewC

@didibus Để diễn giải câu trả lời của bạn ... Biểu tượng cảm xúc mặt cười không phải là giá trị trả về hợp lệ của getUser. Bằng cách kiểm tra getUser, tôi thấy rằng việc triển khai sẽ không bao giờ trả lại biểu tượng cảm xúc mặt cười . Câu hỏi của tôi là, tôi có nên tin tưởng vào sự kiểm tra của mình và không có kiểm tra trong phương pháp của tôi hay tôi nên nghi ngờ về việc kiểm tra của mình và vẫn có một kiểm tra. Cũng có thể phương pháp thay đổi trong tương lai, phá vỡ kỳ vọng của tôi về việc không trả lại biểu tượng cảm xúc mặt cười . Đây không phải là công việc của người gọi để xác nhận rằng hàm được gọi đang thực hiện hợp đồng của nó.
Vince O'Sullivan

@ VinceO'Sullivan Có vẻ như "hợp đồng" là trung tâm của vấn đề. Và câu hỏi của tôi là về các hợp đồng ngầm, so với rõ ràng. Một phương thức trả về int Tôi sẽ không khẳng định rằng tôi không nhận được một chuỗi. Nhưng, nếu tôi chỉ muốn ints tích cực, tôi nên? Nó chỉ ngầm hiểu rằng phương thức không trả về int âm, bởi vì tôi đã kiểm tra nó. Không rõ ràng từ chữ ký hoặc tài liệu mà nó không có.
Didier A.

1
Nó không quan trọng nếu hợp đồng là ngầm hoặc rõ ràng. Đây không phải là công việc của mã gọi để xác thực rằng phương thức được gọi trả về dữ liệu hợp lệ khi được cung cấp dữ liệu hợp lệ. Trong ví dụ của bạn, bạn biết rằng inits tiêu cực không phải là câu trả lời sai nhưng bạn có biết nếu int int là chính xác không? Có bao nhiêu bài kiểm tra bạn thực sự cần, để chứng minh rằng phương pháp này đang hoạt động? Khóa học đúng duy nhất là giả định rằng phương pháp này là chính xác.
Vince O'Sullivan

5

Tôi sẽ lập luận rằng tiền đề của câu hỏi của bạn là tắt: tại sao lại sử dụng tài liệu tham khảo null để bắt đầu?

Mẫu đối tượng null là một cách để trả về các đối tượng mà về cơ bản không làm gì: thay vì trả về null cho người dùng của bạn, trả về một đối tượng đại diện cho "không có người dùng".

Người dùng này sẽ không hoạt động, có tên trống và các giá trị khác null cho biết "không có gì ở đây". Lợi ích chính là bạn không cần xả rác chương trình của bạn sẽ không kiểm tra, ghi nhật ký, v.v. bạn chỉ cần sử dụng các đối tượng của mình.

Tại sao một thuật toán nên quan tâm đến một giá trị null? Các bước nên giống nhau. Thật dễ dàng và rõ ràng hơn khi có một đối tượng null trả về 0, chuỗi trống, v.v.

Dưới đây là một ví dụ về kiểm tra mã cho null:

User u = getUser();
String displayName = "";
if (u != null) {
  displayName = u.getName();
}
return displayName;

Dưới đây là một ví dụ về mã sử dụng một đối tượng null:

return getUser().getName();

Cái nào rõ ràng hơn? Tôi tin rằng thứ hai là.


Trong khi câu hỏi được gắn thẻ , điều đáng chú ý là mẫu đối tượng null thực sự hữu ích trong C ++ khi sử dụng tài liệu tham khảo. Các tham chiếu Java giống như các con trỏ C ++ hơn và cho phép null. Tài liệu tham khảo C ++ không thể giữ nullptr. Nếu ai đó muốn có một cái gì đó tương tự như một tham chiếu null trong C ++, thì mẫu đối tượng null là cách duy nhất tôi biết để thực hiện điều đó.


Null chỉ là ví dụ về những gì tôi khẳng định. Nó rất có thể là tôi cần một cái tên không trống. Câu hỏi của tôi vẫn sẽ được áp dụng, bạn sẽ xác nhận điều đó? Hoặc nó có thể là một cái gì đó trả về một int và tôi không thể có một int âm hoặc nó phải nằm trong một phạm vi nhất định. Đừng nghĩ về nó như một vấn đề vô giá trị mỗi lần nói.
Didier A.

1
Tại sao một phương thức sẽ trả về một giá trị không chính xác? Nơi duy nhất cần kiểm tra là ranh giới của ứng dụng của bạn: giao diện với người dùng và với các hệ thống khác. Mặt khác, đó là lý do tại sao chúng ta có ngoại lệ.

Hãy tưởng tượng tôi đã có: int i = getCount; phao x = 100 / i; Nếu tôi biết getCount không trả về 0, vì tôi đã viết phương thức hoặc đã kiểm tra nó, tôi có nên bỏ qua kiểm tra cho 0 không?
Didier A.

@didibus: bạn có thể bỏ qua kiểm tra nếu getCount() tài liệu đảm bảo rằng nó hiện không trả về 0 và sẽ không làm như vậy trong tương lai ngoại trừ trong trường hợp ai đó quyết định thực hiện thay đổi đột phá và tìm cách cập nhật mọi thứ gọi nó để đối phó giao diện mới. Thấy gì mã hiện đang làm là không có sự giúp đỡ, nhưng nếu bạn đang đi để kiểm tra mã sau đó mã để kiểm tra là các unit test cho getCount(). Nếu họ kiểm tra nó không trả về 0, thì bạn biết bất kỳ thay đổi nào trong tương lai để trả về 0 sẽ được coi là thay đổi vi phạm vì các thử nghiệm sẽ thất bại.
Steve Jessop

Tôi không rõ ràng rằng các đối tượng null tốt hơn null. Một con vịt null có thể quẫy, nhưng nó không phải là một con vịt - trên thực tế, về mặt ngữ nghĩa, nó là phản đề của một con vịt. Khi bạn giới thiệu một đối tượng null, bất kỳ mã nào sử dụng lớp đó có thể phải kiểm tra xem có bất kỳ đối tượng nào của nó là đối tượng null không - ví dụ: bạn có một thứ gì đó rỗng trong một tập hợp, bạn có bao nhiêu thứ? Điều này đối với tôi giống như một cách để trì hoãn thất bại và che giấu lỗi. Bài viết được liên kết đặc biệt cảnh báo không sử dụng các đối tượng null "chỉ để tránh kiểm tra null và làm cho mã dễ đọc hơn".
sdenham

1

Nói chung, tôi muốn nói rằng điều đó phụ thuộc chủ yếu vào ba khía cạnh sau:

  1. mạnh mẽ: phương thức gọi có thể đối phó với nullgiá trị? Nếu một nullgiá trị có thể dẫn đến việc RuntimeExceptiontôi khuyên bạn nên kiểm tra - trừ khi độ phức tạp thấp và các phương thức gọi / gọi được tạo bởi cùng một tác giả và nullkhông được mong đợi (ví dụ: cả hai privatetrong cùng một gói).

  2. trách nhiệm mã: nếu nhà phát triển A chịu trách nhiệm về getUser()phương thức và nhà phát triển B sử dụng nó (ví dụ như một phần của thư viện), tôi thực sự khuyên bạn nên xác thực giá trị của nó. Chỉ vì nhà phát triển B có thể không biết về một thay đổi dẫn đến nullgiá trị lợi nhuận tiềm năng .

  3. độ phức tạp: độ phức tạp tổng thể của chương trình hoặc môi trường càng cao, tôi càng khuyên bạn nên xác thực giá trị trả về. Ngay cả khi bạn cảm thấy chắc chắn về điều đó không thể có nullngày hôm nay trong bối cảnh của phương thức gọi, có thể bạn phải thay đổi getUser()cho một trường hợp sử dụng khác. Một khi vài tháng hoặc vài năm không còn nữa, và hàng ngàn dòng mã đã được thêm vào, đây có thể là một cái bẫy khá khó khăn.

Ngoài ra, tôi khuyên bạn nên ghi nulllại các giá trị trả về tiềm năng trong một nhận xét JavaDoc. Do làm nổi bật các mô tả JavaDoc trong hầu hết các IDE, đây có thể là một cảnh báo hữu ích cho bất kỳ ai sử dụng getUser().

/** Returns ....
  * @param: id id of the user
  * @return: a User instance related to the id;
  *          null, if no user with identifier id exists
 **/
User getUser(Int id)
{
    ...
}

-1

Bạn chắc chắn không phải.

Chẳng hạn, nếu bạn đã biết rằng tiền lãi không bao giờ có thể là null - Tại sao bạn muốn thêm kiểm tra null? Thêm một kiểm tra null sẽ không phá vỡ bất cứ điều gì nhưng nó chỉ là dư thừa. Và tốt hơn không mã logic dự phòng miễn là bạn có thể tránh nó.


1
Tôi biết, nhưng chỉ vì tôi đã kiểm tra hoặc viết triển khai phương pháp khác. Hợp đồng của phương thức không nói rõ ràng rằng nó không thể. Vì vậy, nó có thể, ví dụ, thay đổi trong tương lai. Hoặc nó có thể có một lỗi khiến null trở lại ngay cả khi nó cố gắng không.
Didier A.
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.