Tại sao các tài liệu tham khảo null bị xa lánh trong khi ném ngoại lệ được coi là ổn?


21

Tôi hoàn toàn không hiểu sự bẻ khóa nhất quán của các tài liệu tham khảo null của một số người ngôn ngữ lập trình. Có gì xấu về họ? Nếu tôi yêu cầu quyền truy cập đọc vào một tệp không tồn tại thì tôi hoàn toàn vui mừng khi nhận được một ngoại lệ hoặc tham chiếu null và các ngoại lệ được coi là tốt nhưng tham chiếu null được coi là xấu. Lý do đằng sau này là gì?



2
Một số ngôn ngữ sụp đổ trên null tốt hơn so với những ngôn ngữ khác. Đối với "mã được quản lý", chẳng hạn như .Net / Java, null ref chỉ là một loại vấn đề khác, trong khi mã gốc khác có thể không xử lý vấn đề này một cách duyên dáng (bạn chưa đề cập đến một ngôn ngữ cụ thể). Ngay cả trong một thế giới được quản lý, đôi khi bạn muốn viết mã không an toàn (được nhúng?, Vũ khí?), Và đôi khi bạn muốn làm ầm ĩ ASAP (kiểm tra đơn vị). Cả hai loại mã có thể được gọi vào cùng một thư viện - đó sẽ là một vấn đề. Nói chung tôi nghĩ rằng mã cố gắng không làm tổn thương cảm xúc máy tính là một ý tưởng tồi. Thất bại an toàn là CỨNG.
Công việc

@Job: Đây là chủ trương lười biếng. Nếu bạn biết cách xử lý một ngoại lệ, bạn xử lý nó. Đôi khi việc xử lý đó có thể liên quan đến việc ném một ngoại lệ khác, nhưng bạn không bao giờ nên để một ngoại lệ tham chiếu null không được xử lý. Không bao giờ. Đó là cơn ác mộng của mỗi lập trình viên bảo trì; đó là ngoại lệ vô dụng nhất trong toàn bộ cây. Chỉ cần hỏi Stack Overflow .
Aaronaught

hoặc để đặt nó theo một cách khác - tại sao không trả về một loại mã nào đó để thể hiện thông tin lỗi. Lập luận này sẽ nổi giận trong nhiều năm tới.
gbjbaanb

Câu trả lời:


24

Tài liệu tham khảo Null không "xa lánh" hơn bất kỳ trường hợp ngoại lệ nào, ít nhất là bởi bất kỳ ai tôi từng biết hoặc đọc. Tôi nghĩ bạn đang hiểu sai về sự khôn ngoan thông thường.

Điều tồi tệ là một nỗ lực để truy cập một tham chiếu null (hoặc bỏ qua một con trỏ null, v.v.). Điều này là xấu bởi vì nó luôn luôn chỉ ra một lỗi; bạn sẽ không bao giờ làm điều gì đó như thế này một cách có chủ đích và nếu bạn đang cố tình làm điều đó, thì điều đó còn tồi tệ hơn, bởi vì nó không thể phân biệt hành vi dự kiến ​​với hành vi lỗi.

Có một số nhóm khác nhau ngoài kia, những người thực sự ghét khái niệm vô hiệu vì một số lý do, nhưng như Ed chỉ ra , nếu bạn không có nullhoặc nilsau đó bạn sẽ phải thay thế nó bằng một thứ khác, điều này có thể dẫn đến một cái gì đó tồi tệ hơn một vụ tai nạn (như tham nhũng dữ liệu).

Nhiều khung, trên thực tế, bao gồm cả hai khái niệm; ví dụ, trong .NET, một mẫu thường gặp bạn sẽ thấy là một cặp phương thức, một tiền tố của từ Try(chẳng hạn như TryGetValue). Trong Trytrường hợp, tham chiếu được đặt thành giá trị mặc định của nó (thông thường null) và trong trường hợp khác, một ngoại lệ được đưa ra. Không có gì sai với cả hai cách tiếp cận; cả hai đều được sử dụng thường xuyên trong môi trường hỗ trợ chúng.

Nó thực sự tất cả phụ thuộc vào ngữ nghĩa. Nếu nulllà giá trị trả về hợp lệ, như trong trường hợp chung là tìm kiếm bộ sưu tập, thì trả về null. Mặt khác, nếu đó không phải là giá trị trả về hợp lệ - ví dụ: tra cứu bản ghi bằng khóa chính xuất phát từ cơ sở dữ liệu của bạn - thì việc trả lại nullsẽ là một ý tưởng tồi vì người gọi sẽ không mong đợi và có lẽ sẽ không kiểm tra nó

Nó thực sự rất đơn giản để tìm ra ngữ nghĩa nào sẽ được sử dụng: Liệu nó có ý nghĩa gì đối với kết quả của một hàm không được xác định không? Nếu vậy, bạn có thể trả về một tham chiếu null. Nếu không, ném một ngoại lệ.


5
Trên thực tế, có những ngôn ngữ không có null hoặc không và không "cần thay thế nó bằng thứ khác". Tài liệu tham khảo Nullable ngụ ý rằng có thể có một cái gì đó ở đó, hoặc có thể không có. Nếu bạn chỉ cần yêu cầu người dùng kiểm tra rõ ràng nếu có gì đó ở đó, bạn đã giải quyết vấn đề. Xem haskell cho một ví dụ thực tế cuộc sống.
Johanna Larsson

3
@ErikKronberg, vâng, "sai lầm tỷ đô" và tất cả những điều vô nghĩa đó, cuộc diễu hành của những người đã vạch ra điều này và tuyên bố nó mới mẻ và hấp dẫn không bao giờ kết thúc, đó là lý do tại sao chủ đề bình luận trước đó đã bị xóa. Những sự thay thế mang tính cách mạng mà mọi người không bao giờ thất bại luôn là một số biến thể của Đối tượng, Tùy chọn hoặc Hợp đồng Null, thực sự không loại bỏ một cách kỳ diệu lỗi logic cơ bản, họ chỉ trì hoãn hoặc quảng bá nó, tương ứng. Dù sao, đây rõ ràng là một câu hỏi về ngôn ngữ lập trình mà làmnull, vì vậy thực sự, Haskell là khá không thích hợp ở đây.
Aaronaught

1
Bạn có nghiêm túc lập luận rằng không yêu cầu kiểm tra null cũng tốt như yêu cầu không?
Johanna Larsson

3
@ErikKronberg: Vâng, tôi "lập luận nghiêm túc" rằng việc kiểm tra null không đặc biệt khác với (a) phải thiết kế mọi tầng của ứng dụng xung quanh hành vi của Đối tượng Null, (b) phải khớp mẫu Tùy chọn mọi lúc, hoặc (c) không cho phép callee nói "Tôi không biết" và buộc ngoại lệ hoặc sự cố. Có một lý do tại sao nullđã tồn tại quá lâu, và phần lớn những người nói khác dường như là những học giả có ít kinh nghiệm thiết kế các ứng dụng trong thế giới thực với các ràng buộc như yêu cầu không đầy đủ hoặc tính nhất quán cuối cùng.
Aaronaught

3
@Aaronaught: Đôi khi tôi ước có một nút downvote để bình luận. Không có lý do gì để huênh hoang như thế.
Michael Shaw

11

Sự khác biệt lớn là nếu bạn bỏ mã để xử lý NULL, mã của bạn sẽ tiếp tục có khả năng bị sập ở giai đoạn sau với một số thông báo lỗi không liên quan, trong trường hợp ngoại lệ, ngoại lệ sẽ được nêu ra tại điểm thất bại ban đầu (mở một tập tin để đọc trong ví dụ của bạn).


4
Việc không xử lý NULL sẽ là sự thiếu hiểu biết về giao diện giữa mã của bạn và bất cứ điều gì trả lại nó. Các nhà phát triển sẽ mắc lỗi đó sẽ khiến những người khác nói bằng ngôn ngữ không làm NULL.
Blrfl

@Blrfl, các phương thức lý tưởng là khá ngắn, và do đó thật dễ dàng để tìm ra chính xác nơi xảy ra sự cố. Một trình gỡ lỗi tốt thường có thể săn tốt một ngoại lệ tham chiếu null, ngay cả khi mã dài. Tôi phải làm gì nếu tôi đang cố đọc một cài đặt quan trọng từ sổ đăng ký, không có ở đó? Sổ đăng ký của tôi bị rối và tôi tốt hơn là thất bại và gây khó chịu cho người dùng, hơn là âm thầm tạo lại một nút và đặt nó thành mặc định. Điều gì nếu một virus làm điều này? Vì vậy, nếu tôi nhận được một null, tôi nên ném một ngoại lệ chuyên biệt hay chỉ để cho nó rip? Với phương pháp ngắn thì sự khác biệt lớn là gì?
Công việc

@Job: Nếu bạn không có trình gỡ lỗi thì sao? Bạn có nhận ra rằng 99,99% thời gian ứng dụng của bạn sẽ chạy trong môi trường phát hành không? Khi điều đó xảy ra, bạn sẽ ước rằng bạn đã sử dụng một ngoại lệ có ý nghĩa hơn. Ứng dụng của bạn có thể vẫn phải thất bại và gây khó chịu cho người dùng, nhưng ít nhất nó sẽ xuất ra thông tin gỡ lỗi cho phép bạn theo dõi kịp thời vấn đề, do đó giữ cho sự khó chịu ở mức tối thiểu.
Aaronaught

@Birfl, đôi khi tôi không muốn xử lý trường hợp null sẽ tự nhiên trở lại. Ví dụ: giả sử tôi có các khóa ánh xạ vùng chứa tới các giá trị. Nếu logic của tôi đảm bảo rằng tôi không bao giờ cố đọc các giá trị mà tôi không lưu trữ lần đầu tiên, thì tôi sẽ không bao giờ được trả về null. Trong trường hợp đó, tôi muốn có một ngoại lệ cung cấp càng nhiều thông tin càng tốt để chỉ ra điều gì đã sai, thay vào đó trả về một giá trị null để thất bại một cách bí ẩn ở một nơi nào đó khác trong chương trình.
Winston Ewert

Nói cách khác, ngoại trừ tôi phải xử lý rõ ràng trường hợp bất thường nếu không chương trình của tôi sẽ chết ngay lập tức. Với các tham chiếu null nếu mã không xử lý rõ ràng trường hợp bất thường, nó sẽ cố gắng khập khiễng. Tôi nghĩ rằng tốt hơn để có được trường hợp thất bại bây giờ.
Winston Ewert

8

Bởi vì các giá trị null không phải là một phần cần thiết của ngôn ngữ lập trình và là một nguồn lỗi nhất quán. Như bạn nói, việc mở một tệp có thể dẫn đến thất bại, có thể được truyền trở lại dưới dạng giá trị trả về null hoặc thông qua một ngoại lệ. Nếu giá trị null không được phép thì có một cách duy nhất, duy nhất để giao tiếp thất bại.

Ngoài ra, đây không phải là vấn đề phổ biến nhất với null. Hầu hết mọi người nhớ kiểm tra null sau khi gọi một hàm có thể trả về nó. Vấn đề tăng lên nhiều hơn nữa trong thiết kế của riêng bạn bằng cách cho phép các biến không có giá trị tại các điểm khác nhau trong quá trình thực thi chương trình của bạn. Bạn có thể thiết kế mã của mình sao cho giá trị null không bao giờ được phép, nhưng nếu null không được phép ở cấp ngôn ngữ thì điều này sẽ không cần thiết.

Tuy nhiên, trong thực tế, bạn vẫn sẽ cần một số cách để biểu thị nếu một biến là hoặc không được khởi tạo. Sau đó, bạn sẽ có một dạng lỗi trong đó chương trình của bạn không gặp sự cố, nhưng thay vào đó tiếp tục sử dụng một số giá trị mặc định, không hợp lệ. Tôi thực sự không biết cái nào tốt hơn. Đối với tiền của tôi, tôi thích sụp đổ sớm và thường xuyên.


Hãy xem xét một lớp con Uninitialized với một chuỗi xác định và tất cả các phương thức của nó đưa ra các ngoại lệ. Nếu một trong số này từng xuất hiện, bạn sẽ biết chuyện gì đã xảy ra. Trên các hệ thống nhúng có bộ nhớ hạn chế, phiên bản sản xuất của nhà máy Uninitialized có thể trả về null.
Jim Balter

3
@Jim Balter: Tôi cho rằng tôi bối rối về việc nó sẽ thực sự giúp ích như thế nào trong thực tế. Trong bất kỳ chương trình không tầm thường nào, bạn sẽ phải xử lý tại một số điểm với các giá trị có thể không được khởi tạo. Vì vậy, phải có một số cách để biểu thị một giá trị mặc định. Như vậy, bạn vẫn phải kiểm tra điều này trước khi tiếp tục. Vì vậy, thay vì sự cố có thể xảy ra, giờ đây bạn có khả năng làm việc với dữ liệu không hợp lệ.
Ed S.

1
Bạn cũng biết những gì đã xảy ra khi bạn nhận được nullgiá trị trả về: Thông tin bạn yêu cầu không tồn tại. Không có sự khác biệt. Dù bằng cách nào, người gọi phải xác nhận giá trị trả về nếu thực sự cần sử dụng thông tin đó cho một số mục đích cụ thể. Cho dù nó xác nhận một null, một đối tượng null hoặc một đơn nguyên không có sự khác biệt thực tế.
Aaronaught

1
@Jim Balter: Phải, tôi vẫn không thấy sự khác biệt thực tế và tôi không thấy cách nó giúp mọi người viết chương trình thực tế bên ngoài học viện dễ dàng hơn. Điều đó không có nghĩa là không có lợi ích, đơn giản là chúng dường như không rõ ràng đối với tôi.
Ed S.

1
Tôi đã giải thích sự khác biệt thực tế với một lớp Uninitialized hai lần - nó xác định nguồn gốc của mục null - làm cho nó có thể xác định chính xác lỗi khi xảy ra tình trạng vô hiệu hóa null. Đối với các ngôn ngữ được thiết kế xung quanh các mô hình không có giá trị, chúng sẽ tránh được vấn đề từ việc di chuyển - chúng cung cấp các cách khác để lập trình. Điều đó tránh các biến không được khởi tạo; điều đó có vẻ khó nắm bắt nếu bạn không quen thuộc với chúng. Lập trình có cấu trúc, cũng tránh được một lớp lỗi lớn, cũng từng được coi là "hàn lâm".
Jim Balter

5

Tony Hoare, người đã tạo ra ý tưởng về một tài liệu tham khảo null ngay từ đầu, gọi đó là sai lầm một triệu đô la .

Vấn đề không phải là về các tài liệu tham khảo null mỗi lần, mà là về việc thiếu kiểm tra loại thích hợp trong hầu hết các ngôn ngữ an toàn (loại khác).

Sự thiếu hỗ trợ này, từ ngôn ngữ, có nghĩa là các lỗi "null-bug" có thể ẩn trong chương trình trong một thời gian dài trước khi được phát hiện. Đó là bản chất của lỗi, tất nhiên, nhưng "null-bug" hiện được biết là có thể tránh được.

Vấn đề này đặc biệt xuất hiện trong C hoặc C ++ (ví dụ) do lỗi "cứng" mà nó gây ra (sự cố của chương trình, ngay lập tức, không có phục hồi thanh lịch).

Trong các ngôn ngữ khác, luôn có câu hỏi về cách xử lý chúng.

Trong Java hoặc C #, bạn sẽ nhận được một ngoại lệ nếu bạn cố gắng gọi một phương thức trên một tham chiếu null và nó có thể ổn. Và do đó, hầu hết các lập trình viên Java hoặc C # đã quen với điều này và không hiểu tại sao người ta lại muốn làm khác (và cười vào C ++).

Trong Haskell, bạn phải cung cấp một hành động rõ ràng cho trường hợp null và do đó, các lập trình viên Haskell hả hê với các đồng nghiệp của họ, bởi vì họ đã hiểu đúng (phải không?).

Thực sự, đây là cuộc tranh luận về mã lỗi / ngoại lệ cũ, nhưng lần này với Giá trị Sentinel thay cho mã lỗi.

Như mọi khi thích hợp nhất thực sự phụ thuộc vào tình huống và ngữ nghĩa mà bạn đang tìm kiếm.


Đúng. nullthực sự là xấu xa, bởi vì nó thay thế hệ thống loại . (Được cấp, giải pháp thay thế có một nhược điểm về tính dài dòng của nó, ít nhất là trong một số ngôn ngữ.)
Ốc cơ khí

2

Bạn không thể đính kèm thông báo lỗi có thể đọc được vào con trỏ null.

(Tuy nhiên, bạn có thể để lại thông báo lỗi trong tệp nhật ký.)

Trong một số ngôn ngữ / môi trường cho phép số học con trỏ, nếu một trong các đối số con trỏ là null và được phép tính toán, kết quả sẽ là một con trỏ không hợp lệ , không null . (*) Thêm sức mạnh cho bạn.

(*) Điều này xảy ra rất nhiều trong COM lập trình, nơi mà nếu bạn cố gắng gọi vào một phương pháp giao diện nhưng con trỏ giao diện là null, nó sẽ dẫn đến một cuộc gọi đến một địa chỉ không hợp lệ mà là gần như, nhưng không hoàn toàn, chính xác không giống như bằng không.


2

Trả về NULL (hoặc số 0 hoặc boolean false) để báo hiệu lỗi là sai cả về mặt kỹ thuật và khái niệm.

Về mặt kỹ thuật, bạn đang gánh nặng lập trình viên với việc kiểm tra giá trị trả về ngay lập tức , tại điểm chính xác nơi nó được trả về. Nếu bạn mở hai mươi tệp liên tiếp và việc báo hiệu lỗi được thực hiện bằng cách trả về NULL, thì mã tiêu thụ phải kiểm tra từng tệp được đọc riêng lẻ và thoát ra khỏi bất kỳ vòng lặp và cấu trúc tương tự nào. Đây là một công thức hoàn hảo cho mã lộn xộn. Tuy nhiên, nếu bạn chọn báo hiệu lỗi bằng cách ném một ngoại lệ, mã tiêu thụ có thể chọn xử lý ngoại lệ ngay lập tức hoặc để nó nổi lên nhiều cấp độ phù hợp, thậm chí qua các lệnh gọi hàm. Điều này làm cho mã sạch hơn nhiều.

Về mặt khái niệm, nếu bạn mở một tệp và có lỗi xảy ra, thì việc trả về một giá trị (thậm chí NULL) là sai. Bạn không có gì để quay lại, vì hoạt động của bạn chưa kết thúc. Trả lại NULL là tương đương về mặt khái niệm của "Tôi đã đọc thành công tệp và đây là những gì nó chứa - không có gì". Nếu đó là những gì bạn muốn thể hiện (nghĩa là, nếu NULL có ý nghĩa như là kết quả thực tế cho hoạt động được đề cập), thì bằng mọi cách, hãy trả về NULL, nhưng nếu bạn muốn báo hiệu lỗi, hãy sử dụng ngoại lệ.

Trong lịch sử, các lỗi được báo cáo theo cách này vì các ngôn ngữ lập trình như C không có xử lý ngoại lệ được tích hợp vào ngôn ngữ và cách được đề xuất (sử dụng các bước nhảy dài) là một chút lông và loại phản trực giác.

Ngoài ra còn có một khía cạnh bảo trì cho vấn đề: với các ngoại lệ, bạn phải viết thêm mã để xử lý lỗi; nếu bạn không, chương trình sẽ thất bại sớm và khó khăn (điều này tốt). Nếu bạn trả lại NULL cho các lỗi báo hiệu, hành vi mặc định của chương trình là bỏ qua lỗi và chỉ tiếp tục, cho đến khi nó dẫn đến các vấn đề khác - dữ liệu bị hỏng, segfaults, NullReferenceExceptions, tùy thuộc vào ngôn ngữ. Để báo hiệu lỗi sớm và lớn, bạn phải viết thêm mã và đoán xem: đó là phần bị bỏ sót khi bạn có thời hạn chặt chẽ.


1

Như đã chỉ ra, nhiều ngôn ngữ không chuyển đổi một sự thiếu sót của một con trỏ null thành một ngoại lệ có thể bắt được. Làm điều đó là một thủ thuật tương đối hiện đại. Khi vấn đề con trỏ null được nhận ra lần đầu tiên, các ngoại lệ thậm chí chưa được phát minh.

Nếu bạn cho phép con trỏ null là trường hợp hợp lệ, đó là trường hợp đặc biệt. Bạn cần logic xử lý trường hợp đặc biệt, thường ở nhiều nơi khác nhau. Đó là sự phức tạp thêm.

Cho dù nó có liên quan đến con trỏ có khả năng null hay không, nếu bạn không sử dụng các cú ném ngoại lệ để xử lý các trường hợp ngoại lệ, bạn phải xử lý các trường hợp ngoại lệ đó theo một cách khác. Thông thường, mọi lệnh gọi hàm phải được kiểm tra cho các trường hợp ngoại lệ đó, để ngăn chặn lệnh gọi hàm được gọi không phù hợp hoặc để phát hiện trường hợp lỗi khi hàm thoát. Đó là sự phức tạp thêm có thể tránh được bằng cách sử dụng các ngoại lệ.

Phức tạp hơn thường có nghĩa là nhiều lỗi hơn.

Các lựa chọn thay thế cho việc sử dụng con trỏ null trong cấu trúc dữ liệu (ví dụ: để đánh dấu điểm bắt đầu / kết thúc của danh sách được liên kết) bao gồm sử dụng các mục sentinel. Chúng có thể cung cấp các chức năng tương tự với độ phức tạp ít hơn nhiều. Tuy nhiên, có thể có những cách khác để quản lý sự phức tạp. Một cách là bọc con trỏ null có khả năng trong một lớp con trỏ thông minh để việc kiểm tra null chỉ cần ở một nơi.

Phải làm gì với con trỏ null khi nó được phát hiện? Nếu bạn không thể xây dựng trong xử lý trường hợp ngoại lệ, bạn luôn có thể đưa ra một ngoại lệ và ủy thác hiệu quả việc xử lý trường hợp đặc biệt đó cho người gọi. Và đó chính xác là những gì một số ngôn ngữ làm theo mặc định khi bạn hủy đăng ký một con trỏ null.


1

Cụ thể đối với C ++, nhưng có các tham chiếu null bị xa lánh bởi vì ngữ nghĩa null trong C ++ được liên kết với các loại con trỏ. Nó khá hợp lý khi một hàm mở tệp bị lỗi và trả về một con trỏ null; trong thực tế fopen()chức năng làm chính xác điều đó.


Thật vậy, nếu bạn thấy mình có một tham chiếu null trong C ++, đó là do chương trình của bạn đã bị hỏng .
Kaz Dragon

1

Nó phụ thuộc vào ngôn ngữ.

Chẳng hạn, Objective-C cho phép bạn gửi tin nhắn đến một đối tượng null (nil) mà không gặp vấn đề gì. Một cuộc gọi đến nil cũng trả về nil và được coi là một tính năng ngôn ngữ.

Cá nhân tôi thích nó vì bạn có thể dựa vào hành vi đó và tránh tất cả những if(obj == null)cấu trúc lồng nhau phức tạp đó .

Ví dụ:

if (myObject != nil && [myObject doSomething])
{
    ...
}

Có thể rút ngắn thành:

if ([myObject doSomething])
{
    ...
}

Nói tóm lại, nó làm cho mã của bạn dễ đọc hơn.


0

Tôi không đưa ra một trò chơi khăm cho dù bạn trả về null hay ném ngoại lệ, miễn là bạn ghi lại.


Và cũng đặt tên cho nó: GetAddressMaybehoặc GetSpouseNameOrNull.
rwong

-1

Một tham chiếu Null thường xảy ra vì một cái gì đó trong logic chương trình đã bị bỏ qua, tức là: bạn đã nhận được một dòng mã mà không cần phải thiết lập yêu cầu cho khối mã đó.

Mặt khác, nếu bạn ném một ngoại lệ cho một cái gì đó, điều đó có nghĩa là bạn đã nhận ra rằng một tình huống cụ thể có thể xảy ra trong hoạt động bình thường của chương trình và nó đã được xử lý.


2
Một tài liệu tham khảo null có thể "xảy ra" vì rất nhiều lý do, rất ít trong số chúng liên quan đến bất cứ điều gì bị bỏ lỡ. Có thể bạn cũng đang bị nhầm lẫn với một ngoại lệ tham chiếu null .
Aaronaught

-1

Tài liệu tham khảo Null thường rất hữu ích: Ví dụ, một yếu tố trong danh sách được liên kết có thể có một số người kế nhiệm hoặc không có người kế nhiệm. Sử dụng nullcho "không có người kế nhiệm" là hoàn toàn tự nhiên. Hoặc, một người có thể có vợ / chồng hoặc không - sử dụng nullcho "người không có vợ / chồng" là hoàn toàn tự nhiên, tự nhiên hơn nhiều so với giá trị "không có vợ / chồng" mà Person.Spousethành viên có thể đề cập.

Nhưng: Nhiều giá trị không phải là tùy chọn. Trong một chương trình OOP điển hình, tôi muốn nói rằng hơn một nửa số tài liệu tham khảo không thể nullsau khi khởi tạo, nếu không chương trình sẽ thất bại. Nếu không, mã sẽ phải được if (x != null)kiểm tra bằng séc. Vậy tại sao mọi tham chiếu nên được null theo mặc định? Nó thực sự phải là một cách khác: mặc định các biến không phải là nullable và bạn rõ ràng phải nói "oh, và giá trị này cũng có thể như nullvậy".


Có điều gì từ cuộc thảo luận này mà bạn muốn thêm lại vào câu trả lời của mình không? Chủ đề bình luận này đã có một chút nóng, và chúng tôi muốn làm sạch nó. Bất kỳ cuộc thảo luận mở rộng nên được thực hiện để trò chuyện .

Ở giữa tất cả những cuộc cãi lộn đó, có thể có một hoặc hai điểm quan tâm thực sự. Thật không may, tôi đã không thấy bình luận của Mark cho đến khi tôi cắt lại cuộc thảo luận mở rộng. Trong tương lai, vui lòng gắn cờ câu trả lời của bạn cho người điều hành chú ý nếu bạn muốn giữ lại các bình luận cho đến khi bạn có thời gian để xem xét chúng và chỉnh sửa câu trả lời của bạn một cách thích hợp.
Josh K

-1

Câu hỏi của bạn là từ khó hiểu. Bạn có nghĩa là một ngoại lệ tham chiếu null (mà thực sự gây ra bởi một nỗ lực để hủytham chiếu null)? Lý do rõ ràng để không muốn loại ngoại lệ đó là vì nó không cung cấp cho bạn thông tin nào về sự cố, hoặc ngay cả khi - giá trị có thể được đặt thành null tại bất kỳ thời điểm nào trong chương trình. Bạn viết "Nếu tôi yêu cầu quyền truy cập đọc vào một tệp không tồn tại thì tôi rất vui khi nhận được một ngoại lệ hoặc tham chiếu null" - nhưng bạn không nên hoàn toàn vui mừng khi nhận được một cái gì đó không có dấu hiệu nguyên nhân . Không ở đâu trong chuỗi "một nỗ lực đã được thực hiện để hủy đăng ký null" có bất kỳ đề cập nào về việc đọc hoặc các tệp không tồn tại. Có lẽ bạn có nghĩa là bạn sẽ hoàn toàn hạnh phúc khi nhận được giá trị null như một giá trị trả về từ một cuộc gọi đọc - đó là một vấn đề hoàn toàn khác, nhưng nó vẫn không cung cấp cho bạn thông tin về lý do tại sao việc đọc thất bại; nó '


Không, tôi không có nghĩa là một ngoại lệ tham chiếu null. Trong tất cả các ngôn ngữ tôi biết chưa được khởi tạo nhưng các biến được khai báo là một số dạng null.
davidk01

Nhưng câu hỏi của bạn không phải là về các biến chưa được khởi tạo. Và có những ngôn ngữ không sử dụng null cho các biến chưa được khởi tạo, mà thay vào đó sử dụng các đối tượng trình bao bọc có thể tùy ý chứa một giá trị - ví dụ Scala và Haskell.
Jim Balter

1
"... nhưng thay vào đó sử dụng các đối tượng trình bao bọc có thể tùy ý chứa một giá trị ." Mà rõ ràng không có gì giống như một loại nullable .
Aaronaught

1
Trong haskell không có thứ gọi là biến chưa được khởi tạo. Bạn có khả năng có thể khai báo IORef và chọn nó với giá trị ban đầu nhưng không giống với việc khai báo một biến trong một ngôn ngữ khác và khiến nó không được khởi tạo với tất cả các vấn đề tương tự. Làm việc trong lõi hoàn toàn chức năng bên ngoài các lập trình viên IO monad haskell không có cách truy vấn các loại tham chiếu nên không có vấn đề tham chiếu null.
davidk01

1
Nếu bạn có một giá trị "Thiếu" đặc biệt, thì đó chính xác giống như một giá trị "null" đặc biệt - nếu bạn có sẵn các công cụ tương tự để xử lý nó. Đó là một chữ "nếu" đáng kể. Bạn cần thêm độ phức tạp để xử lý trường hợp đó. Trong Haskell, khớp mẫu và hệ thống loại cung cấp một cách để giúp quản lý sự phức tạp đó. Tuy nhiên, có những công cụ khác để quản lý sự phức tạp trong các ngôn ngữ khác. Ngoại lệ là một công cụ như vậy.
Steve314
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.