2009-05-13 25 views
12

Tại sao String.indexOf không sử dụng ngoại lệ nhưng trả lại -1 khi không tìm thấy chuỗi con?Tại sao String.indexOf không sử dụng ngoại lệ nhưng trả về -1 khi không tìm thấy chuỗi con?

Mục đích của câu hỏi này là: khi chúng tôi bắt đầu ngoại lệ tùy chỉnh.

Tôi tin rằng tránh sự cần thiết phải trả lại mã lỗi đặc biệt là đường dẫn thiết kế phù hợp.

Ý kiến ​​của bạn là gì?

+0

Như bạn có thể thấy từ các câu trả lời, không ai nghĩ rằng nó phải là một ngoại lệ. Hãy tự hỏi, nếu nó trả về Integer thay cho int, bạn có mong đợi nó trả về null hay ném một ngoại lệ. Vì nó là một nguyên thủy, null không có sẵn như là một kiểu trả về, do đó -1 được sử dụng để thay thế. – Robin

+0

nếu nó trả về đối tượng Integer. null là có thể. tham khảo MSFT.net 2.0, int? là giải pháp tốt – ariso

Trả lời

24

Theo nguyên tắc, nếu mục đích của phương pháp là kiểm tra thứ gì đó, thì việc thiếu một thứ gì đó không phải là ngoại lệ. Nếu phương pháp giả định rằng một cái gì đó là đúng, thì sự vắng mặt của cái gì đó sẽ là một ngoại lệ. Vì vậy, "File.exists()" không ném một FileNotFoundException, nhưng "File.open()" hiện.

+0

Tôi nghĩ Paul có câu trả lời đúng. vì tệp.exists() không ném ngoại lệ. – ariso

18

ngoại lệ dành cho các trường hợp ngoại lệ, khi một chuỗi không chứa một chữ cái, điều đó hầu như không đặc biệt, trừ khi bạn đang sử dụng nó cho một số trường hợp cực đoan. Nếu đó là những gì bạn đang làm, bạn luôn có thể chọn để ném ngoại lệ của riêng bạn.

+3

+1 cho "ngoại lệ dành cho trường hợp ngoại lệ". Người ta có thể hỏi, "tại sao File.exists() không cho phép FileNotFoundException thay vì trả về false"? Khái niệm tương tự; bạn gọi cả hai phương pháp trong kiến ​​thức rằng nó rất có khả năng cho tình trạng là tiêu cực. – Rob

+0

Có lẽ nó được coi là khá bình thường đối với một tập tin không tồn tại, nếu không tại sao có một phương pháp để kiểm tra cho nó hơn là chỉ giả định các tập tin bạn yêu cầu là có được ở đó. –

3

Sẽ dễ dàng hơn nhiều khi đối phó với việc kiểm tra -1 hơn là bắt ngoại lệ.

3

Cũng vì ngoại lệ là tốn kém về mặt hiệu suất

1

Tôi nghĩ rằng người ta phải ném một ngoại lệ khi một cái gì đó bất ngờ xảy ra. Điều đó nói rằng, một chuỗi con không tìm thấy trong một String không phải là bất ngờ, có thể xảy ra, nó là một kết quả hợp lý.

Tôi đồng ý với bạn rằng người ta nên cố gắng tránh trả lại mã lỗi, nhưng trong trường hợp này chúng tôi chỉ có hai lựa chọn, tìm thấy chuỗi hoặc chuỗi không tìm thấy.

15

qua tôi nghe trên đó là ...

'Bạn ném một ngoại lệ khi phương pháp của bạn không thể làm những gì nó hứa hẹn sẽ' - Jeff Richter CVC 2nd ed

  • IndexOf() hứa hẹn bạn trả về chỉ mục của lần xuất hiện đầu tiên của một chuỗi/chuỗi. Nó có thể đã ném một ngoại lệ nếu nó không thể làm công việc của mình vì một lý do nào đó. Nó đã làm công việc của mình nhưng không tìm thấy chuỗi và do đó trả về -1 để truyền đạt kết quả không tìm thấy.
  • File.Open() sẽ ném một FileNotException cho một tập tin không tồn tại vì nó không thể làm những gì nó hứa hẹn .. tức là mở tập tin được chỉ định.
+2

Thêm ý kiến ​​của Paul ở đây.Khi quy tắc chung, nếu mục đích của phương pháp là kiểm tra thứ gì đó, thì việc thiếu một thứ gì đó không nên là ngoại lệ. Nếu phương pháp giả định rằng một cái gì đó là đúng, thì sự vắng mặt của cái gì đó sẽ là một ngoại lệ. Vì vậy, "File.exists()" không ném một FileNotFoundException, nhưng "File.open()" hiện. – ariso

+1

+1 cho Paul. Nó theo sau từ báo giá ở trên, Bất kỳ kết quả có thể có/giá trị trả về nào trong trường hợp phương thức thành công nên * không * ở dạng ngoại lệ. Phương pháp này chỉ nên ném một ngoại lệ để cho biết rằng nó không thể thực hiện nhiệm vụ/lý do của nó. – Gishu

+0

Lỗi nằm ở phía của chuỗi (vì nó không có chuỗi bạn tìm kiếm), không phải ở phía phương thức. –

3

Ngoài các đối số chống lại ngoại lệ nói chung, tôi sẽ thêm -1 đó có thể là kết quả hữu ích từ indexOf và lastIndexOf, không chỉ là giá trị đặc biệt. Ví dụ: để phân tích cú pháp tên tệp từ một chuỗi có thể có hoặc không chứa đường dẫn:

String filename = arg.substring(arg.lastIndexOf('/') + 1); 

Mặc dù có thể là ví dụ giả tạo, điều này sẽ hơi cồng kềnh hơn với ngoại lệ.

+1

Một vấn đề của thực tế, tôi sẽ xem xét việc này một hack. Đó là một cái đẹp, nhưng vẫn còn, nó không rõ ràng các nhà phát triển đến sau khi bạn sẽ hiểu. Ít nhất hãy sử dụng nhận xét ... – sleske

+0

@Sleske A hack? Một giá trị trả về hữu ích không phải là một hack. Một lời bình luận? Bạn muốn thêm điều gì chưa được nêu trong JavaDoc của các hàm (đơn giản) này? – eljenso

+3

@eljenso - Tôi đồng ý rằng 'hack' có thể hơi mạnh. Nhưng nhìn vào mã KHÔNG làm cho nó ý định rõ ràng. Một lập trình viên khác có thể dễ dàng xem xét điều này và nghĩ rằng tác giả 'bỏ lỡ' trường hợp không có '/'. Thông minh và bảo trì không phải lúc nào cũng đi đôi với nhau. – kenj0418

2

Rất nhiều câu trả lời hay tại đây. Đây là một vấn đề thiết kế, nơi chủ nghĩa thực dụng đã được ưu tiên hơn "quy tắc" sau đây.Trong trường hợp này, có một số "quy tắc" mâu thuẫn:

  • tránh sử dụng các giá trị đặc biệt như dữ liệu trở lại (không tự chủ tài liệu, đòi hỏi nhà phát triển để xử lý giá trị đặc biệt theo một cách riêng biệt từ mã khác)

vs

  • không ném ngoại lệ trong quá trình thực thói quen mã, chỉ khi có điều gì bất ngờ xảy ra

Tôi đồng ý với quyết định thiết kế này. Tuy nhiên, nếu bạn không, bạn luôn có thể viết mã của riêng mình để kiểm tra sự tồn tại của chuỗi trước khi kiểm tra chỉ mục của nó. Đừng là tù nhân của ngôn ngữ của bạn, uốn cong nó theo ý muốn của bạn. Ngôn ngữ có nghĩa là bị tra tấn!

6

trả về -1 gần như khủng khiếp như ném một ngoại lệ. Cách chính xác sẽ là sử dụng loại tùy chọn nếu ngôn ngữ chỉ hỗ trợ tốt hơn. Trong tình hình bình thường, nơi có kết quả, bạn quấn kết quả trong đối tượng và trả về điều đó. Nếu không, bạn trả về một đối tượng đại diện cho tình huống "không phải kết quả".

Trong trang web cuộc gọi, bạn phải kiểm tra xem đó là trang web nào; bạn không thể chỉ sử dụng giá trị trả về vì loại siêu của chúng, chúng phải được kiểm tra thông qua khớp mẫu.

Trong cú pháp giả:

class Option[a] = Some[a] | None, 

nơi một là tham số kiểu chung chung, Một số đại diện cho một kết quả có giá trị và Không không kết quả không có giá trị.

trong trường hợp indexOf bạn sẽ phải:

Option[Integer] indexOf(char c) = { 
    if(found) return Some(index) 
    else return None 
} 

và bạn sử dụng theo cách này:

result = "uncle".indexOf('c') 
result match { 
    Some(i) => System.out.println("index was: " + i); 
    None => System.out.println("no value"); 
} 

Nếu bạn bỏ qua một số hoặc None từ phù hợp (công tắc đó là kinda khái quát hóa), trình biên dịch sẽ cảnh báo bạn.

+0

Java không phải là Haskell. Và -1 có thể là giá trị trả về * hữu ích * khi thao tác Strings. Vì vậy, trở lại -1 là xa khủng khiếp trong Java, và chắc chắn không phải là khủng khiếp như ném một ngoại lệ. – eljenso

+1

Ngoại lệ sẽ không bị chú ý, nhưng có thể logic chương trình của bạn sẽ âm thầm phát ra khi bạn đang xử lý một số. Plus -1 không có bất kỳ giá trị dễ đọc nào. Chỉ là một giá trị tùy ý. – egaga

+0

Tôi đồng ý. ném ngoại lệ sẽ làm cho mã hoàn chỉnh hơn và không dễ hiểu ... – ariso

0

Cho đến khi tác giả của Java string.indexOf cho chúng ta biết lịch sử thực tế ...

Giả sử chúng ta phải thiết kế nó từ đầu, một số hạn chế về thiết kế rõ ràng cho vấn đề này:

  1. indexOf phải trả lại một giá trị số, để khi tìm thấy kết quả phù hợp, bạn biết vị trí của nó là
  2. chỉ mục hợp lệ được đảm bảo luôn là số nguyên
  3. chỉ mục mảng (và chuỗi) không dựa trên Java
  4. Java được mạnh mẽ gõ
  5. số nguyên kiểu dữ liệu được ký kết trong Java

Với những hạn chế cơ bản, một số lựa chọn có thể cho chức năng quay trở lại gõ sẽ là số nguyên (lý tưởng của một loại đủ lớn để đại diện cho chỉ mục cuối cùng trong chuỗi có thể lớn nhất), HOẶC ... Object (và có thể trả về null để chỉ ra không tìm thấy).Nhưng trong thực tế trả lại Object sẽ không hiệu quả và cũng không thân thiện với người dùng, do cần kiểm tra tính hợp lệ của nó và truyền trước khi sử dụng cho trường hợp tìm thấy - vì vậy nó không thực sự là một lựa chọn khả thi!

Vì vậy, hãy đi với một số nguyên. Chúng ta có muốn ném một ngoại lệ nếu không tìm thấy? Ném ngoại lệ có nhiều vấn đề của riêng nó - tạo ra các đối tượng ngoại lệ và nhảy tới các trình xử lý ngoại lệ có thể khá kém hiệu quả, và viết các khối try/catch xung quanh các cuộc gọi indexOf cũng không vui!

Vì vậy, giả sử chúng tôi đã thu hẹp nó xuống: nó phải trả lại một loại số nguyên (đã ký) và không ném một ngoại lệ. Bây giờ giá trị số nguyên nào sẽ trở lại để biểu diễn không tìm thấy?

Để cho phép tìm kiếm trong chuỗi càng lớn càng tốt, chúng tôi nên đặt trước tất cả các số nguyên dương cho việc sử dụng như ý nghĩa tìm thấy thành công. Ngược lại, không có số âm nào là cần thiết để biểu thị chỉ mục 'tìm thấy', vì vậy tất cả đều có khả năng sử dụng làm mã trả về đại diện cho 'không tìm thấy'.

Nếu chúng tôi có thể chọn bất kỳ số âm nào, đại diện cho không tìm thấy hoặc chỉ nói 'tất cả giá trị trả về tiêu cực có nghĩa là không tìm thấy' nó sẽ thực hiện công việc ... Nhưng đó có phải là thiết kế tốt nhất không?

Một số lý do để sử dụng -1 thay vì các số âm khác là gì? Lý do yêu thích của tôi đơn giản là '-1 rất dễ để mọi người nhớ, và bạn có thể thực hiện các bài kiểm tra bình đẳng chính xác trên đó'. (Thay vì bị buộc phải sử dụng sự bất bình đẳng và suy nghĩ về các vấn đề off-by-one như bạn muốn ít hơn hoặc ít hơn hoặc bằng nhau, và giá trị nào để so sánh, không hoặc tiêu cực)

I đôi khi cũng ngưỡng mộ lý do của Chris rằng (diễn giải) 'nó hoạt động độc đáo với substring(foundIndex + 1)'.

Các vấn đề liên quan