Phương thức truy xuất nên trả về 'null' hoặc ném ngoại lệ khi nó không thể tạo ra giá trị trả về? [đóng cửa]


503

Tôi có một phương thức được cho là trả về một đối tượng nếu nó được tìm thấy.

Nếu nó không được tìm thấy, tôi nên:

  1. trả về null
  2. ném một ngoại lệ
  3. khác

57
Bất cứ điều gì bạn làm, hãy chắc chắn rằng bạn tài liệu nó. Tôi nghĩ rằng điểm này quan trọng hơn chính xác phương pháp nào là "tốt nhất".
Rik

6
Điều này phụ thuộc vào các thành ngữ phổ biến của ngôn ngữ lập trình. Vui lòng gắn thẻ câu hỏi này với một thẻ ngôn ngữ lập trình.
Teddy

3
Trả về null chỉ có nghĩa là thành công hay thất bại mà thường không có nhiều thông tin (một số phương pháp có thể thất bại theo nhiều cách). Các thư viện tốt hơn nên đưa ra các ngoại lệ để làm rõ các lỗi và bằng cách này, chương trình chính có thể quyết định cách xử lý lỗi ở mức cao hơn (ngược lại với logic xử lý lỗi dựng sẵn).
3k-

1
Dường như với tôi rằng câu hỏi thực sự đang được hỏi là liệu chúng ta có nên xem nó là ngoại lệ đối với một thực thể không được tìm thấy hay không, và nếu vậy, tại sao? Không ai thực sự trả lời đầy đủ làm thế nào để đi đến kết luận đó, và bây giờ Q & A đã kết thúc. Một sự xấu hổ thực sự rằng ngành công nghiệp đã không đi đến thống nhất về chủ đề quan trọng này. Vâng, tôi biết nó phụ thuộc . Vì vậy, giải thích lý do tại sao nó phụ thuộc nhiều hơn "nếu đặc biệt, ném"
đè bẹp

Câu trả lời:


484

Nếu bạn luôn mong muốn tìm thấy một giá trị thì hãy ném ngoại lệ nếu nó bị thiếu. Ngoại lệ có nghĩa là có một vấn đề.

Nếu giá trị có thể bị thiếu hoặc hiện tại và cả hai đều hợp lệ cho logic ứng dụng thì trả về null.

Quan trọng hơn: Bạn làm gì ở những nơi khác trong mã? Tính nhất quán là quan trọng.


30
@Ken: +1, thật tuyệt khi đề cập rằng nếu bạn ném ngoại lệ, nhưng có thể phát hiện ra đó là một tiên nghiệm (như HasItem (...)), thì người dùng nên cung cấp phương thức Has * hoặc Chứa.
user7116

4
Thay vì trả về giá trị hoặc null khi giá trị bị thiếu, hãy xem xét trả về Có thể <T>. Xem mikehadlow.blogspot.nl/2011/01/monads-in-c-5-maybe.html .
Erwin Rooijakkers

2
Theo cách lựa chọn thiết kế @ErwinRooijakkers , kể từ Java 8, bạn cũng có thể trả lại một tùy chọn <T>
José Andias

2
Tôi thấy có một chút xáo trộn mỗi câu trả lời lặp lại cùng một câu tục ngữ: "Nếu nó đặc biệt, hãy ném đi." Hầu hết các kỹ sư sẽ làm quen với nguyên tắc này. Theo tôi, câu hỏi thực sự ở đây là làm thế nào để xác định xem nó có nên được coi là ngoại lệ hay không. OP đang tìm kiếm thực tiễn tốt nhất liên quan đến một cái gì đó giống như một mẫu kho lưu trữ chẳng hạn. Có phải nó thường được coi là ngoại lệ cho một đối tượng không tồn tại được cung cấp khóa chính? Vâng, đó là điều mà miền của anh ấy sẽ xác định, nhưng hầu hết các chuyên gia có nhiều năm kinh nghiệm đề xuất điều gì? Đó là loại câu trả lời chúng ta nên xem.
nghiền nát

4
@crush Tôi nghĩ rằng một hiệu trưởng hướng dẫn là những tham số nào được truyền cho hàm . Nếu bạn vượt qua một danh tính , giống như bạn đề cập đến một khóa chính, thì nó sẽ được coi là ngoại lệ nếu không tìm thấy mục đó, nó chỉ ra trạng thái không nhất quán trong hệ thống. Ví dụ: GetPersonById(25)sẽ ném nếu người đó đã bị xóa, nhưng GetPeopleByHairColor("red")sẽ trả về một kết quả trống. Vì vậy, tôi nghĩ rằng các thông số nói lên điều gì đó về sự mong đợi.
John Knoop

98

Chỉ ném một ngoại lệ nếu nó thực sự là một lỗi. Nếu đó là hành vi dự kiến ​​cho đối tượng không tồn tại, trả về null.

Nếu không thì đó là vấn đề ưu tiên.


4
Tôi không đồng ý. Bạn có thể ném ngoại lệ dưới dạng mã trạng thái: "NotFoundException"
ACV

Nó chắc chắn không nên là một vấn đề ưu tiên. Đó là cách chúng tôi kết thúc với mã không nhất quán - nếu không nằm trong mã nhóm của bạn, thì gần như chắc chắn khi đan xen mã nhà phát triển khác với mã của riêng bạn (thư viện bên ngoài).
nghiền nát

4
Tôi nghĩ rằng việc xử lý trường hợp null dễ dàng hơn nhiều so với "NotFoundException". Hãy suy nghĩ về bao nhiêu dòng bắt bạn phải viết xung quanh mỗi yêu cầu đối thủ duy nhất ném ra "NotFoundException" ... Thật đau đớn khi sẵn sàng tất cả mã đó trong mắt tôi.
visc

tôi muốn trích dẫn Tony Hoare: "Tôi gọi đó là sai lầm tỷ đô của tôi". Tôi sẽ không trả về null, tôi sẽ ném ngoại lệ và xử lý chính xác hoặc trả lại một đối tượng trống.
bảy

70

Như một quy tắc chung, nếu phương thức luôn luôn trả về một đối tượng, thì đi với ngoại lệ. Nếu bạn dự đoán null thường xuyên và muốn xử lý nó theo một cách nhất định, hãy đi với null.

Dù bạn làm gì, tôi khuyên bạn nên chống lại tùy chọn thứ ba: Trả lại một chuỗi có nội dung "WTF".


Thêm một vì trong những ngày xưa tốt đẹp tôi đã làm điều đó nhiều hơn một vài lần như là một sửa chữa "tạm thời" bẩn thỉu nhanh chóng ... không có ý tưởng tốt. Đặc biệt nếu nó sẽ được xem xét nếu bạn là một sinh viên.
rciafardone

14
Tôi sẽ bỏ phiếu vì các tùy chọn WTF có vẻ tuyệt vời đối với tôi ... nhưng rõ ràng tôi có một trái tim
đánh dấu

5
ném WtfExcepti😲n mới
Kamafeather

Tôi nghĩ sẽ hữu ích nếu câu trả lời này nói về lý do tại sao một phương thức luôn trả về một đối tượng so với "một giá trị không thường xuyên". Những gì đảm bảo loại tình huống? Cho một ví dụ về khi một tình huống như vậy có thể tồn tại.
nghiền nát

51

Nếu null không bao giờ chỉ ra lỗi thì chỉ cần trả về null.

Nếu null luôn là một lỗi thì ném ngoại lệ.

Nếu null đôi khi là một ngoại lệ thì mã hai thói quen. Một thường trình đưa ra một ngoại lệ và cái còn lại là một thói quen kiểm tra boolean trả về đối tượng trong một tham số đầu ra và thường trình trả về sai nếu không tìm thấy đối tượng.

Thật khó để sử dụng sai thói quen Thử. Thật dễ dàng để quên kiểm tra null.

Vì vậy, khi null là một lỗi bạn chỉ cần viết

object o = FindObject();

Khi null không phải là lỗi, bạn có thể mã hóa cái gì đó như

if (TryFindObject(out object o)
  // Do something with o
else
  // o was not found

1
Đây sẽ là một gợi ý hữu ích hơn nếu C # cung cấp các bộ dữ liệu thực, vì vậy chúng tôi có thể tránh sử dụng tham số [out]. Tuy nhiên, đây là mẫu ưa thích, vì vậy +1.
Erik Forbes

2
Theo tôi, phương pháp thử là cách tốt nhất. Bạn không cần phải tìm kiếm những gì xảy ra nếu đối tượng không thể được trả lại. Với phương pháp Thử, bạn biết ngay phải làm gì.
OregonGhost

nhắc nhở tôi findfindOrFailtừ Laravel Eloquent
vivoconunxino

@ErikForbes Tôi biết nhận xét của bạn đã cũ, nhưng liệu câu trả lời có phải là xác định một đối tượng đa thuộc tính sẽ được trả về từ TryFindObjectphương thức không? Tuples dường như là một mô hình lười biếng cho các lập trình viên, những người không muốn dành thời gian để xác định một đối tượng gói gọn nhiều giá trị. Đó là về cơ bản tất cả các bộ dữ liệu là cốt lõi.
nghiền nát

@crush - Được đặt tên là Tuple Văn học là một lựa chọn, IMO. Đây là một liên kết đến một mẫu không đồng bộ Thử với các bộ dữ liệu. stackoverflow.com/questions/1626597/
hy

26

Tôi chỉ muốn tóm tắt lại các tùy chọn được đề cập trước đó, ném một số tùy chọn mới vào:

  1. trả về null
  2. ném một ngoại lệ
  3. sử dụng mẫu đối tượng null
  4. cung cấp một tham số boolean cho phương thức của bạn, để người gọi có thể chọn nếu anh ta muốn bạn đưa ra một ngoại lệ
  5. cung cấp một tham số phụ, để người gọi có thể đặt giá trị mà anh ta nhận lại nếu không tìm thấy giá trị

Hoặc bạn có thể kết hợp các tùy chọn sau:

Cung cấp một số phiên bản quá tải của getter của bạn, để người gọi có thể quyết định đường nào để đi. Trong hầu hết các trường hợp, chỉ có cái đầu tiên có triển khai thuật toán tìm kiếm và những cái khác chỉ bao quanh cái đầu tiên:

Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);

Ngay cả khi bạn chọn chỉ cung cấp một triển khai, bạn có thể muốn sử dụng quy ước đặt tên như thế để làm rõ hợp đồng của mình và điều đó cũng giúp bạn nên quyết định thêm các triển khai khác.

Bạn không nên quá lạm dụng nó, nhưng nó có thể hữu ích, đặc biệt khi viết Lớp trợ giúp mà bạn sẽ sử dụng trong hàng trăm ứng dụng khác nhau với nhiều quy ước xử lý lỗi khác nhau.


Tôi thích các tên hàm rõ ràng, đặc biệt là orCreate và orDefault.
marcotwout 14/07/2015

5
Hầu hết trong số này có thể được sạch hơn bằng văn bản với Expected<T> findObject(String)nơi Expected<T>có các chức năng orNull(), orThrow(), orSupplied(Supplier<T> supplier), orDefault(T default). Điều này trừu tượng hóa việc nhận dữ liệu từ việc xử lý lỗi
WorldSEnder

Tôi đã không biết về Dự kiến ​​<T> cho đến bây giờ. Tôi dường như khá mới và có thể không tồn tại khi tôi viết câu trả lời ban đầu. Có lẽ bạn nên làm cho nhận xét của bạn một câu trả lời thích hợp.
Lena Schimmel

Ngoài ra, Dự kiến ​​<T> là một mẫu C ++. Có triển khai nó trong các ngôn ngữ hướng đối tượng khác không?
Lena Schimmel

Trong Java 8, trả về Tùy chọn <T> (được gọi là Có thể <T>, v.v. bằng các ngôn ngữ khác) cũng là một tùy chọn. Điều này chỉ ra rõ ràng cho người gọi rằng không trả lại được gì là khả năng và sẽ không biên dịch nếu người gọi không xử lý khả năng đó, trái với null, dù sao (trong Java) sẽ biên dịch ngay cả khi người gọi không kiểm tra nó .
Một số chàng trai

18

Sử dụng mẫu đối tượng null hoặc ném ngoại lệ.


Đây là câu trả lời thực sự. Trả lại null là một thói quen khủng khiếp của các lập trình viên lười biếng.
jeremyjjbrown

Tôi không thể tin rằng câu trả lời này chưa được bình chọn lên hàng đầu. Đây là câu trả lời thực sự, và một trong hai cách tiếp cận rất dễ dàng và tiết kiệm rất nhiều mã hóa hoặc NPE.
Bane


3
Nếu một người sử dụng mẫu đối tượng null, làm thế nào người ta phân biệt trường hợp khóa được ánh xạ tới đối tượng null với trường hợp khóa không có ánh xạ? Tôi nghĩ rằng việc trả lại một đối tượng vô nghĩa sẽ tồi tệ hơn nhiều so với việc trả về null. Trả về null cho mã không được chuẩn bị để xử lý nó thường sẽ dẫn đến một ngoại lệ bị ném. Không phải là sự lựa chọn tối ưu của ngoại lệ, nhưng dù sao cũng là một ngoại lệ. Trả lại một đối tượng vô nghĩa có nhiều khả năng dẫn đến mã không chính xác liên quan đến dữ liệu vô nghĩa là chính xác.
supercat

3
Làm thế nào các đối tượng null hành xử cho một tra cứu thực thể? Ví dụ, Person somePerson = personRepository.find("does-not-exist");giả sử phương thức này trả về một đối tượng null cho ID does-not-exist. Điều gì sau đó sẽ là hành vi chính xác cho somePerson.getAge()? Ngay bây giờ, tôi chưa tin rằng mẫu đối tượng null là giải pháp phù hợp cho việc tra cứu thực thể.
Abdull

13

Hãy thống nhất với (các) API bạn đang sử dụng.


13

Ưu điểm của việc ném ngoại lệ:

  1. Kiểm soát dòng chảy sạch hơn trong mã gọi của bạn. Kiểm tra null tiêm một nhánh có điều kiện được xử lý bằng cách thử / bắt. Kiểm tra null không cho biết bạn đang kiểm tra cái gì - bạn đang kiểm tra null vì bạn đang tìm kiếm một lỗi mà bạn đang mong đợi hoặc bạn đang kiểm tra null để bạn không vượt qua nó trên downchain ?
  2. Loại bỏ sự mơ hồ về ý nghĩa của "null". Là đại diện null của một lỗi hoặc là null những gì thực sự được lưu trữ trong giá trị? Khó có thể nói khi bạn chỉ có một điều để dựa trên quyết tâm đó.
  3. Cải thiện tính nhất quán giữa hành vi phương thức trong một ứng dụng. Các ngoại lệ thường được phơi bày trong chữ ký phương thức, vì vậy bạn có thể hiểu các trường hợp cạnh trong các tài khoản ứng dụng và thông tin nào mà ứng dụng của bạn có thể phản ứng theo cách có thể dự đoán được.

Để biết thêm giải thích với các ví dụ, xem: http://metatations.com/2011/11/17/retinating-null-vs-throwing-an-exception/


2
+1 vì điểm 2 là tuyệt vời - null không có nghĩa tương tự như không tìm thấy. Điều này trở nên quan trọng hơn khi xử lý các ngôn ngữ động trong đó Null thực sự có thể là đối tượng được lưu trữ / truy xuất bởi hàm - và trong trường hợp đó
Adam Terrey

1
+1 cho điểm # 2. Là một lỗi không? Là null những gì được lưu trữ cho khóa đã cho? Là null chỉ ra rằng khóa không tồn tại? Đây là những câu hỏi thực sự khiến cho việc trả lại null rõ ràng gần như không bao giờ đúng. Đây có thể là câu trả lời tốt nhất ở đây vì những người khác vừa mới đưa ra câu trả lời mơ hồ "Nếu nó đặc biệt, hãy ném"
nghiền nát

12

nó phụ thuộc nếu ngôn ngữ và mã của bạn quảng bá: LBYL (xem trước khi bạn nhảy) hoặc EAFP (dễ xin tha thứ hơn là cho phép)

LBYL nói rằng bạn nên kiểm tra các giá trị (vì vậy trả về null)
EAFP nói chỉ cần thử thao tác và xem nếu nó không thành công (ném ngoại lệ)

mặc dù tôi đồng ý với ở trên .. ngoại lệ nên được sử dụng cho các điều kiện ngoại lệ / lỗi và trả về null là tốt nhất khi sử dụng séc.


EAFP so với LBYL trong Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html ( Lưu trữ web )


3
Trong một số trường hợp, EAFP là cách tiếp cận có ý nghĩa duy nhất. Ví dụ, trong một bản đồ / từ điển đồng thời, không có cách nào để hỏi liệu ánh xạ có tồn tại khi được yêu cầu hay không.
supercat

11

Chỉ cần tự hỏi: "đó có phải là một trường hợp đặc biệt mà đối tượng không được tìm thấy" không? Nếu điều đó được dự kiến ​​sẽ xảy ra trong quá trình bình thường của chương trình của bạn, có lẽ bạn không nên đưa ra một ngoại lệ (vì đó không phải là hành vi đặc biệt).

Phiên bản ngắn: sử dụng ngoại lệ để xử lý hành vi đặc biệt, không xử lý luồng kiểm soát thông thường trong chương trình của bạn.

-Alan.


5

Các ngoại lệ có liên quan đến Thiết kế theo Hợp đồng.

Giao diện của một đối tượng thực sự là một hợp đồng giữa hai đối tượng, người gọi phải đáp ứng hợp đồng nếu không người nhận có thể thất bại với một ngoại lệ. Có hai hợp đồng có thể

1) tất cả đầu vào phương thức là hợp lệ, trong trường hợp đó bạn phải trả về null khi không tìm thấy đối tượng.

2) chỉ một số đầu vào là hợp lệ, nghĩa là kết quả trong một đối tượng tìm thấy. Trong trường hợp đó, bạn PHẢI đưa ra một phương thức thứ hai cho phép người gọi xác định xem liệu đầu vào của nó có đúng không. Ví dụ

is_present(key)
find(key) throws Exception

NẾU và CHỈ NẾU bạn cung cấp cả hai phương thức của hợp đồng thứ 2, bạn được phép ném ngoại lệ là không tìm thấy gì!


4

Tôi thích chỉ trả về một null, và dựa vào người gọi để xử lý nó một cách thích hợp. Ngoại lệ (vì thiếu một từ tốt hơn) là nếu tôi hoàn toàn 'chắc chắn' thì phương thức này sẽ trả về một đối tượng. Trong trường hợp đó, một thất bại là một ngoại lệ nên và nên ném.


4

Phụ thuộc vào những gì nó có nghĩa là không tìm thấy đối tượng.

Nếu đó là một trạng thái bình thường, sau đó trả về null. Đây chỉ là một cái gì đó có thể xảy ra một lần trong một thời gian, và người gọi nên kiểm tra nó.

Nếu đó là một lỗi, sau đó đưa ra một ngoại lệ, người gọi sẽ quyết định phải làm gì với tình trạng lỗi của đối tượng bị thiếu.

Cuối cùng, một trong hai sẽ hoạt động, mặc dù hầu hết mọi người thường coi đó là cách thực hành tốt để chỉ sử dụng Ngoại lệ khi một cái gì đó, tốt, ngoại lệ đã xảy ra.


2
Làm thế nào bạn sẽ giải thích về tuyên bố " tình trạng thông thường " và bạn sẽ sử dụng tiêu chí nào để phân biệt nó với một lỗi.
dùng1451111

4

Dưới đây là một vài gợi ý.

Nếu trả về một bộ sưu tập, tránh trả về null, hãy trả lại một bộ sưu tập trống, giúp việc liệt kê dễ dàng hơn để xử lý mà không cần kiểm tra null trước.

Một số API .NET sử dụng mẫu tham số throwOnError, cho phép người gọi lựa chọn xem đó có thực sự là một tình huống đặc biệt hay không nếu không tìm thấy đối tượng. Type.GetType là một ví dụ về điều này. Một mẫu phổ biến khác với BCL là mẫu TryGet trong đó boolean được trả về và giá trị được truyền qua một tham số đầu ra.

Bạn cũng có thể xem xét mẫu Null Object trong một số trường hợp có thể là mặc định hoặc phiên bản không có hành vi. Điều quan trọng là tránh kiểm tra null trong toàn bộ cơ sở mã. Xem tại đây để biết thêm thông tin http://geekswithbloss.net/dseller/archive/2006/09/08/90656.aspx


3

Trong một số chức năng tôi thêm một tham số:

..., bool verify = true)

Đúng có nghĩa là ném, sai có nghĩa là trả về một số giá trị trả về lỗi. Bằng cách này, bất cứ ai sử dụng chức năng này đều có cả hai tùy chọn. Mặc định là đúng, vì lợi ích của những người quên xử lý lỗi.


3

Trả về null thay vì ném một ngoại lệ và ghi lại rõ ràng khả năng giá trị trả về null trong tài liệu API. Nếu mã gọi không tôn trọng API và kiểm tra trường hợp null, rất có thể nó sẽ dẫn đến một loại "ngoại lệ con trỏ null" nào đó :)

Trong C ++, tôi có thể nghĩ ra 3 hương vị khác nhau khi thiết lập một phương thức tìm thấy một đối tượng.

Lựa chọn A

Object *findObject(Key &key);

Trả về null khi không thể tìm thấy đối tượng. Đẹp và đơn giản. Tôi sẽ đi với cái này Các phương pháp thay thế dưới đây dành cho những người không ghét các nhân viên khác.

Lựa chọn B

void findObject(Key &key, Object &found);

Truyền tham chiếu đến biến sẽ nhận đối tượng. Phương thức đưa ra một ngoại lệ khi không thể tìm thấy một đối tượng. Quy ước này có lẽ phù hợp hơn nếu nó không thực sự được mong đợi cho một đối tượng không được tìm thấy - do đó bạn đưa ra một ngoại lệ để biểu thị rằng đó là một trường hợp bất ngờ.

Tùy chọn C

bool findObject(Key &key, Object &found);

Phương thức trả về false khi không thể tìm thấy một đối tượng. Ưu điểm của tùy chọn A này là bạn có thể kiểm tra trường hợp lỗi trong một bước rõ ràng:

if (!findObject(myKey, myObj)) { ...

3

Chỉ đề cập đến trường hợp null không được coi là một hành vi đặc biệt, tôi chắc chắn cho phương pháp thử, rõ ràng, không cần phải "đọc sách" hoặc "nhìn trước khi bạn nhảy" như đã nói ở đây

nên về cơ bản:

bool TryFindObject(RequestParam request, out ResponseParam response)

và điều này có nghĩa là mã của người dùng cũng sẽ rõ ràng

...
if(TryFindObject(request, out response)
{
  handleSuccess(response)
}
else
{
  handleFailure()
}
...

2

Nếu điều quan trọng đối với mã máy khách là biết sự khác biệt giữa tìm thấy và không tìm thấy và đây được coi là một hành vi thông thường, thì tốt nhất là trả về null. Mã khách hàng sau đó có thể quyết định phải làm gì.


2

Nói chung nó sẽ trả về null. Mã gọi phương thức sẽ quyết định nên ném ngoại lệ hay thử thứ khác.


2

Hoặc trả lại Tùy chọn

Một tùy chọn về cơ bản là một lớp container buộc khách hàng xử lý các trường hợp gian hàng. Scala có khái niệm này, tra cứu API của nó.

Sau đó, bạn có các phương thức như T getOrElse (T value IfNull) trên đối tượng này, hoặc trả về đối tượng tìm thấy hoặc một đặc tả của máy khách.


2

Thích trả về null -

Nếu người gọi sử dụng nó mà không kiểm tra, ngoại lệ sẽ xảy ra ngay tại đó.

Nếu người gọi không thực sự sử dụng nó, đừng đánh thuế anh ta try/ catchkhối


2

Thật không may, JDK không nhất quán, nếu bạn cố truy cập khóa không tồn tại trong gói tài nguyên, bạn sẽ không tìm thấy ngoại lệ và khi bạn yêu cầu giá trị từ bản đồ, bạn sẽ nhận được null nếu nó không tồn tại. Vì vậy, tôi sẽ thay đổi câu trả lời của người chiến thắng thành như sau, nếu giá trị tìm thấy có thể là null, sau đó đưa ra ngoại lệ khi không tìm thấy, nếu không trả về null. Vì vậy, hãy tuân theo quy tắc với một ngoại lệ, nếu bạn cần biết tại sao giá trị không được tìm thấy thì luôn tăng ngoại lệ hoặc ..


1

Miễn là nó phải trả lại một tham chiếu đến đối tượng, trả về NULL là tốt.

Tuy nhiên, nếu nó trả lại toàn bộ điều đẫm máu (như trong C ++ nếu bạn làm: 'return blah;' thay vì 'return & blah;' (hoặc 'blah' là một con trỏ), thì bạn không thể trả lại NULL, vì đó là không thuộc loại 'đối tượng'. Trong trường hợp đó, ném một ngoại lệ hoặc trả lại một đối tượng trống không có cờ thành công là cách tôi sẽ tiếp cận vấn đề.


1

Đừng nghĩ rằng bất cứ ai đề cập đến chi phí xử lý ngoại lệ - cần có thêm tài nguyên để tải lên và xử lý ngoại lệ, trừ khi đó là sự kiện giết chết ứng dụng thực sự hoặc quá trình dừng (tiến lên sẽ gây hại nhiều hơn lợi) Tôi sẽ chọn trả lại giá trị môi trường gọi có thể giải thích khi nó thấy phù hợp.


1

Tôi đồng ý với những gì có vẻ là sự đồng thuận ở đây (trả về null nếu "không tìm thấy" là kết quả bình thường có thể xảy ra hoặc ném ngoại lệ nếu ngữ nghĩa của tình huống yêu cầu luôn tìm thấy đối tượng).

Tuy nhiên, có khả năng thứ ba có thể có ý nghĩa tùy thuộc vào tình huống cụ thể của bạn. Phương thức của bạn có thể trả về một đối tượng mặc định thuộc loại nào đó trong điều kiện "không tìm thấy", cho phép mã cuộc gọi được đảm bảo rằng nó sẽ luôn nhận được một đối tượng hợp lệ mà không cần kiểm tra null hoặc bắt ngoại lệ.


1

Trả về null, ngoại lệ chính xác là: điều mà mã của bạn không được mong đợi.



1

Nếu phương thức trả về một bộ sưu tập, thì trả về một bộ sưu tập trống (như đã nói ở trên). Nhưng xin vui lòng không Bộ sưu tập.EMPTY_LIST hoặc như vậy! (trong trường hợp Java)

Nếu phương thức lấy lại một đối tượng, thì Bạn có một số tùy chọn.

  1. Nếu phương thức luôn luôn tìm kết quả và đó là trường hợp ngoại lệ thực sự không tìm thấy đối tượng, thì bạn nên đưa ra một ngoại lệ (trong Java: vui lòng không kiểm tra Ngoại lệ)
  2. (Chỉ dành cho Java) Nếu bạn có thể chấp nhận rằng phương thức đưa ra một ngoại lệ được kiểm tra, hãy ném ObjectNotFoundException cụ thể của dự án hoặc tương tự. Trong trường hợp này, trình biên dịch sẽ nói với bạn nếu bạn quên xử lý ngoại lệ. (Đây là cách xử lý ưa thích của tôi đối với những thứ không tìm thấy trong Java.)
  3. Nếu bạn nói nó thực sự ổn, nếu không tìm thấy đối tượng và tên Phương thức của bạn giống như findBookForAuthorOrReturnNull (..), thì bạn có thể trả về null. Trong trường hợp này nó được mạnh recomminded sử dụng một số loại séc tĩnh hoặc kiểm tra trình biên dịch, ngăn ngừa Mà dereferencing của kết quả mà không cần một tấm séc null. Trong trường hợp của Java, nó có thể là ví dụ. FindBugs (xem DefaultAnnotation tại http://findbugs.sourceforge.net/manual/annotations.html ) hoặc IntelliJ-Checking.

Hãy cẩn thận, nếu bạn quyết định trả về null. Nếu bạn không phải là lập trình viên duy nhất trong dự án, bạn sẽ nhận được NullPulumExceptions (bằng Java hoặc bất kỳ ngôn ngữ nào khác) trong thời gian chạy! Vì vậy, đừng trả về null mà không được kiểm tra tại thời điểm biên dịch.


Không nếu mã được viết đúng để mong đợi null. Xem câu trả lời được bình chọn hàng đầu để biết thêm.
Andrew Barber

Nhưng chỉ khi bạn đảm bảo tại thời điểm biên dịch, tất cả null đều được kiểm tra. Điều này có thể được thực hiện, sử dụng FindBugs @NutNull ở cấp gói và đánh dấu phương thức của bạn là "có thể trả về null". Hoặc để sử dụng một ngôn ngữ như Kotlin hoặc Nice. Nhưng nó đơn giản hơn nhiều để không trả về null.
iuzuz

"Đơn giản hơn", có thể . Nhưng thường không chính xác
Andrew Barber

1
Một lần nữa: Đọc câu trả lời được bình chọn hàng đầu để biết thêm thông tin. Về cơ bản: Nếu đó là kết quả có thể được mong đợi mà cuốn sách được yêu cầu không thể tìm thấy, thì ngoại lệ là điều sai lầm khi không tìm thấy cuốn sách được yêu cầu, trái ngược với một số lỗi xảy ra.
Andrew Barber

1
Bạn đang hiểu lầm rất nhiều ở đây. Bạn đang áp dụng lời khuyên có điều kiện trên toàn cầu, điều này gần như luôn luôn là một điều xấu. Đọc phần còn lại của các câu trả lời bỏ phiếu, quá. Câu trả lời của bạn chỉ nêu một cách tuyệt đối và trình bày logic cực kỳ sai lầm cho nó.
Andrew Barber

1

Nếu bạn đang sử dụng một thư viện này hay cách khác lớp mà ném một ngoại lệ, bạn nên rethrow nó. Đây là một ví dụ. Example2.java giống như thư viện và example.java sử dụng đối tượng của nó. Main.java là một ví dụ để xử lý Ngoại lệ này. Bạn sẽ hiển thị một thông điệp có ý nghĩa và (nếu cần) ngăn xếp theo dõi cho người dùng ở phía gọi.

Main.java

public class Main {
public static void main(String[] args) {
    Example example = new Example();

    try {
        Example2 obj = example.doExample();

        if(obj == null){
            System.out.println("Hey object is null!");
        }
    } catch (Exception e) {
        System.out.println("Congratulations, you caught the exception!");
        System.out.println("Here is stack trace:");
        e.printStackTrace();
    }
}
}

Ví dụ

/**
 * Example.java
 * @author Seval
 * @date 10/22/2014
 */
public class Example {
    /**
     * Returns Example2 object
     * If there is no Example2 object, throws exception
     * 
     * @return obj Example2
     * @throws Exception
     */
    public Example2 doExample() throws Exception {
        try {
            // Get the object
            Example2 obj = new Example2();

            return obj;

        } catch (Exception e) {
            // Log the exception and rethrow
            // Log.logException(e);
            throw e;
        }

    }
}

Ví dụ2.java

 /**
 * Example2.java
 * @author Seval
 *
 */
public class Example2 {
    /**
     * Constructor of Example2
     * @throws Exception
     */
    public Example2() throws Exception{
        throw new Exception("Please set the \"obj\"");
    }

}

Nếu ngoại lệ được ném ra khỏi hàm không phải là ngoại lệ thời gian chạy và người gọi dự kiến ​​sẽ xử lý nó (thay vì chỉ chấm dứt chương trình), thì thay vì ném ngoại lệ từ hệ thống con nội bộ mà người gọi không thể mong đợi, sẽ tốt hơn nếu bọc ngoại lệ bên trong bằng một ngoại lệ được kiểm tra bên ngoài, trong khi 'xâu chuỗi' ngoại lệ bên trong để ai đó gỡ lỗi có thể tìm ra lý do tại sao ngoại lệ bên ngoài bị ném. Chẳng hạn, example1 có thể sử dụng 'throw MyCheckedException mới ("Vui lòng đặt \" obj \ "", e)' để bao gồm 'e' trong ngoại lệ được ném.
Một số chàng trai

0

Điều đó thực sự phụ thuộc vào việc bạn có mong muốn tìm thấy đối tượng hay không. Nếu bạn theo trường phái suy nghĩ rằng các ngoại lệ nên được sử dụng để chỉ ra điều gì đó, tốt, lỗi, ngoại lệ đã xảy ra sau đó:

  • Đối tượng tìm thấy; trả lại đối tượng
  • Đối tượng không tìm thấy; ném ngoại lệ

Nếu không, trả về 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.