Giải pháp đúng cách trong Java: phân tích cú pháp 2 số từ 2 chuỗi và sau đó trả về tổng của chúng


84

Một câu hỏi khá ngu ngốc. Đưa ra mã:

public static int sum(String a, String b) /* throws? WHAT? */ {
  int x = Integer.parseInt(a); // throws NumberFormatException
  int y = Integer.parseInt(b); // throws NumberFormatException
  return x + y;
}

Bạn có thể biết đó là Java tốt hay không? Những gì tôi đang nói đến là, NumberFormatExceptionlà một ngoại lệ chưa được kiểm tra. Bạn không cần phải chỉ định nó như một phần của sum()chữ ký. Hơn nữa, theo như tôi hiểu, ý tưởng của các ngoại lệ không được kiểm tra chỉ là để báo hiệu rằng việc triển khai chương trình là không chính xác, và thậm chí nhiều hơn nữa, bắt các ngoại lệ không được kiểm tra là một ý tưởng tồi, vì nó giống như sửa chương trình xấu trong thời gian chạy .

Ai đó vui lòng làm rõ liệu:

  1. Tôi nên chỉ định NumberFormatExceptionnhư một phần của chữ ký của phương thức.
  2. Tôi nên xác định ngoại lệ đã kiểm tra của riêng mình ( BadDataException), xử lý NumberFormatExceptionbên trong phương thức và ném lại nó dưới dạng BadDataException.
  3. Tôi nên xác định ngoại lệ đã kiểm tra của riêng mình ( BadDataException), xác thực cả hai chuỗi theo cách nào đó như biểu thức chính quy và ném của tôi BadDataExceptionnếu nó không khớp.
  4. Ý tưởng của bạn?

Cập nhật :

Hãy tưởng tượng, nó không phải là một framework mã nguồn mở mà bạn nên sử dụng vì một số lý do. Bạn nhìn vào chữ ký của phương thức và nghĩ - "OK, nó không bao giờ ném". Sau đó, một ngày nào đó, bạn có một ngoại lệ. Nó có bình thường không?

Cập nhật 2 :

Có một số ý kiến ​​nói rằng của tôi sum(String, String)là một thiết kế tồi. Tôi hoàn toàn đồng ý, nhưng đối với những người tin rằng vấn đề ban đầu sẽ không bao giờ xuất hiện nếu chúng tôi có thiết kế tốt, đây là một câu hỏi bổ sung:

Định nghĩa vấn đề là như thế này: bạn có một nguồn dữ liệu nơi các số được lưu trữ dưới dạng Strings. Nguồn này có thể là tệp XML, trang web, cửa sổ màn hình nền với 2 hộp chỉnh sửa, bất cứ thứ gì.

Mục tiêu của bạn là thực hiện logic lấy 2 Strings này, chuyển chúng thành ints và hiển thị hộp thông báo cho biết "tổng là xxx".

Bất kể phương pháp tiếp cận bạn sử dụng để thiết kế / triển khai điều này là gì, bạn sẽ có 2 điểm chức năng bên trong :

  1. Nơi bạn chuyển đổi Stringthànhint
  2. Nơi bạn thêm 2 intgiây

Câu hỏi chính của bài đăng gốc của tôi là:

Integer.parseInt()mong đợi chuỗi chính xác được chuyển. Bất cứ khi nào bạn vượt qua một chuỗi xấu , điều đó có nghĩa là chương trình của bạn không chính xác (không phải " người dùng của bạn là một tên ngốc"). Bạn cần triển khai đoạn mã mà một mặt bạn có Integer.parseInt () với ngữ nghĩa PHẢI và mặt khác, bạn cần chấp nhận các trường hợp đầu vào không chính xác - NÊN ngữ nghĩa .

Vì vậy, ngắn gọn: làm cách nào để triển khai ngữ nghĩa NÊN nếu tôi chỉ có thư viện PHẢI .


13
Đó hoàn toàn không phải là một câu hỏi ngu ngốc. Trên thực tế, nó là một trong những khá tốt! Tôi không hoàn toàn chắc chắn, tôi sẽ chọn phương án nào.
martin

1
Đối với bản cập nhật của bạn: Vâng, theo nguyên tắc không nhanh thì điều này cũng không nhất thiết là một điều xấu.
Johan Sjöberg

1
Tôi đồng ý với martin. Đó là một trong những khía cạnh của lập trình Java mà người ta ít hiểu nhất, đòi hỏi một số phương pháp hay nhất. Điều này có thể được nhìn thấy bởi việc thiếu các trang về chủ đề với rất ít trang ngoài việc O'Reilly nói "đây là cách nó nên được thực hiện".
James P.

2
Trên thực tế, đây là một câu hỏi tuyệt vời.
Chris Cudmore

1
Câu hỏi tuyệt vời! Cũng nêu ra một số câu trả lời tuyệt vời: D
Kheldar

Câu trả lời:


35

Đây là một câu hỏi hay. Tôi ước nhiều người sẽ nghĩ về những điều như vậy.

IMHO, việc ném các ngoại lệ không được chọn có thể chấp nhận được nếu bạn đã được chuyển các thông số rác.

Nói chung, bạn không nên ném BadDataExceptionvì bạn không nên sử dụng Ngoại lệ để kiểm soát luồng chương trình. Những trường hợp ngoại lệ dành cho những điều đặc biệt. Những người gọi đến phương thức của bạn có thể biết trước khi họ gọi nó nếu chuỗi của họ là số hay không, vì vậy việc chuyển rác vào là điều có thể tránh được và do đó có thể được coi là một lỗi lập trình , có nghĩa là bạn có thể ném các ngoại lệ không được kiểm tra.

Về việc khai báo throws NumberFormatException- điều này không hữu ích lắm, vì sẽ ít người nhận thấy do NumberFormatException bị bỏ chọn. Tuy nhiên, IDE có thể tận dụng nó và cung cấp try/catchmột cách chính xác. Một lựa chọn tốt là sử dụng cả javadoc, ví dụ:

/**
 * Adds two string numbers
 * @param a
 * @param b
 * @return
 * @throws NumberFormatException if either of a or b is not an integer
 */
public static int sum(String a, String b) throws NumberFormatException {
    int x = Integer.parseInt(a); 
    int y = Integer.parseInt(b); 
    return x + y;
}

CHỈNH SỬA :
Những người bình luận đã đưa ra những điểm hợp lệ. Bạn cần xem xét cách sử dụng phần mềm này và thiết kế tổng thể của ứng dụng.

Nếu phương thức sẽ được sử dụng khắp nơi và điều quan trọng là tất cả người gọi xử lý sự cố, thì khai báo phương thức như ném một ngoại lệ đã được kiểm tra (buộc người gọi giải quyết vấn đề), nhưng làm lộn xộn mã với try/catchcác khối.

Mặt khác, nếu chúng ta đang sử dụng phương pháp này với dữ liệu mà chúng ta tin tưởng, thì hãy khai báo nó như trên, bởi vì nó sẽ không bao giờ phát nổ và bạn tránh được sự lộn xộn mã của try/catchcác khối cơ bản không cần thiết .


6
Vấn đề là các ngoại lệ không được kiểm tra thường bị bỏ qua và có thể tràn vào ngăn xếp cuộc gọi của bạn, tàn phá các phần của ứng dụng mà bạn không biết điều gì nằm bên dưới. Câu hỏi thực sự là bit mã nào nên kiểm tra xem đầu vào có hợp lệ hay không.
G_H

1
@G_H có lý. Các hướng dẫn Java nói thế này: "Nếu một ứng dụng khách có thể được mong đợi một cách hợp lý để khôi phục từ một ngoại lệ, hãy đặt nó thành một ngoại lệ đã được kiểm tra. Nếu một ứng dụng khách không thể làm bất cứ điều gì để khôi phục từ ngoại lệ, hãy đặt nó thành một ngoại lệ không được kiểm tra". Câu hỏi đặt ra là nên RuntimeExceptionxử lý ở đâu? Nó nên là người gọi hay nên để Ngoại lệ nổi lên? Nếu có thì phải xử lý như thế nào?
James P.

1
Để trả lời một phần cho điều này, tôi đã thấy hai cách tiếp cận: đầu tiên là chặn Exceptionstừ các lớp thấp hơn và bọc chúng trong các Ngoại lệ cấp cao hơn có ý nghĩa hơn đối với người dùng cuối và cách thứ hai là sử dụng một trình xử lý ngoại lệ không cần thiết có thể được khởi tạo trong trình khởi chạy ứng dụng.
James P.

2
IMHO có NumberFormatException trong javadoc là nhiều quan trọng hơn. Đặt nó trong throwsmệnh đề là một sự bổ sung hay, nhưng không bắt buộc.
Dorus

3
Để "Người gọi phương thức của bạn có thể biết trước khi họ gọi nó nếu chuỗi của họ có phải là số hay không, vì vậy việc chuyển rác vào là điều có thể tránh được" : Điều đó không thực sự đúng. Cách đơn giản duy nhất để xác minh rằng một chuỗi phân tích cú pháp int là dùng thử. Mặc dù bạn có thể muốn thực hiện một số kiểm tra trả trước, nhưng kiểm tra chính xác là một PITA.
maaartinus

49

Theo ý kiến ​​của tôi, tốt hơn là nên xử lý logic ngoại lệ càng xa càng tốt. Do đó tôi thích chữ ký hơn

 public static int sum(int a, int b);

Với chữ ký phương pháp của bạn, tôi sẽ không thay đổi bất cứ điều gì. Hoặc bạn là

  • Có lập trình sử dụng các giá trị không chính xác, thay vào đó bạn có thể xác thực thuật toán nhà sản xuất của mình
  • hoặc gửi các giá trị từ ví dụ: đầu vào của người dùng, trong trường hợp đó mô-đun đó sẽ thực hiện xác nhận

Do đó, xử lý ngoại lệ trong trường hợp này trở thành một vấn đề tài liệu .


4
Tôi thích điều này. Nó buộc người dùng phải tuân theo hợp đồng và làm cho phương thức chỉ làm một việc.
Chris Cudmore

Tôi không hiểu cách sử dụng phương pháp này có gì khác so với cách người dùng thực hiện a + b. Tại sao chúng ta cần phương pháp này?
Swati

4
@Swati: Tôi nghĩ đó là một ví dụ , đó là một kỹ thuật tuyệt vời để hiển thị mọi thứ một cách đơn giản. Phương pháp tổng hợp cũng có thể là myVeryComplicatedMethodWhichComputesPhoneNumberOfMyIdealMatchGirl (int myid, int myLifeExpectancy) ...
Kheldar

3
Hoàn toàn đồng ý ở đây. một sumhàm mong đợi hai số, sẽ nhận được hai số. Cách bạn nhận được những thứ đó không liên quan đến sumchức năng. Phân tách logic của bạn một cách chính xác . Vì vậy, tôi muốn liên hệ điều này với một vấn đề thiết kế.
c00kiemon5ter

5

Số 4. Như đã cho, phương thức này không nên lấy chuỗi làm tham số mà nó phải lấy số nguyên. Trong trường hợp đó (vì java kết thúc thay vì tràn) không có khả năng xảy ra ngoại lệ.

 x = sum(Integer.parseInt(a), Integer.parseInt(b))

rõ ràng hơn rất nhiều về những gì có nghĩa là x = sum(a, b)

Bạn muốn ngoại lệ xảy ra càng gần nguồn (đầu vào) càng tốt.

Đối với các tùy chọn 1-3, bạn không xác định một ngoại lệ bởi vì bạn mong đợi người gọi của bạn giả định rằng nếu không thì mã của bạn không thể bị lỗi, bạn xác định một ngoại lệ để xác định những gì xảy ra trong các điều kiện lỗi đã biết MÀ KHÔNG PHẢI LÀ PHƯƠNG PHÁP CỦA BẠN. Tức là nếu bạn có một phương thức là một trình bao bọc xung quanh một đối tượng khác và nó ném một ngoại lệ thì hãy chuyển nó đi. Chỉ khi ngoại lệ là duy nhất đối với phương thức của bạn thì bạn mới nên ném một ngoại lệ tùy chỉnh (frex, trong ví dụ của bạn, nếu tổng được cho là chỉ trả về kết quả dương tính, thì việc kiểm tra điều đó và ném một ngoại lệ sẽ phù hợp, nếu mặt khác java đã ném một ngoại lệ tràn thay vì gói, sau đó bạn sẽ chuyển nó đi cùng, không xác định nó trong chữ ký của bạn, đổi tên nó hoặc ăn nó).

Cập nhật để trả lời cập nhật của câu hỏi:

Vì vậy, ngắn gọn: làm cách nào để triển khai ngữ nghĩa NÊN nếu tôi chỉ có thư viện PHẢI.

Giải pháp cho điều này là bọc thư viện PHẢI và trả về giá trị NÊN. Trong trường hợp này, một hàm trả về một Số nguyên. Viết một hàm nhận một chuỗi và trả về một đối tượng Integer - nó hoạt động hoặc nó trả về null (như Ints.tryParse của ổi). Việc xác thực của bạn có tách biệt khỏi hoạt động của bạn không, hoạt động của bạn sẽ có ints. Việc hoạt động của bạn có được gọi với các giá trị mặc định khi bạn có đầu vào không hợp lệ hay bạn làm điều gì khác, sẽ phụ thuộc vào thông số kỹ thuật của bạn - hầu hết tôi có thể nói về điều đó, đó là thực sự không chắc nơi đưa ra quyết định đó là trong hoạt động phương pháp.


Ý tưởng của bạn ở đây là gì? Tôi sẽ gặp vấn đề tương tự ngay cả khi tôi có sum(int, int)parseIntFromString(String). Để có được chức năng tương tự, trong cả hai trường hợp, tôi sẽ phải viết một đoạn mã trong đó có 2 cuộc gọi đến parseIntFromString()và 1 cuộc gọi đến sum(). Hãy xem xét trường hợp này, nếu nó có ý nghĩa với bạn - tôi thấy không có gì khác biệt so với quan điểm của vấn đề ban đầu.
Andrey Agibalov

@ loki2302: vấn đề là người gọi sẽ quyết định hành vi nào là phù hợp khi đó không phải là một số. Ngoài ra, nếu họ không thực hiện kiểm tra lỗi thì lỗi xảy ra một bước gần nơi giá trị được chỉ định - đối với mục đích gỡ lỗi, càng gần nhiệm vụ, việc gỡ lỗi càng dễ dàng. Và bạn có nhiều khả năng bỏ lỡ việc viết bài kiểm tra đơn vị thích hợp cho người gọi nếu bạn đang thực hiện TDD. Về cơ bản, bạn không muốn có một chuỗi được cung cấp trong phương thức x được cho là một số và sau đó 5 lớp và 20 lần gọi phương thức sau đó sẽ đưa ra một ngoại lệ khi bạn cố gắng coi nó là một số.
jmoreno

Tôi không hiểu. Bạn đang cố gắng nói rằng việc cung cấp một giao diện int sum(String, String)không bao giờ khả thi trong thực tế?
Andrey Agibalov

1
@ loki2302: Với đoạn mã được hiển thị, nó sẽ có thể nhưng một ý tưởng tồi. Nếu số trong chuỗi có thể là một từ trong đó "2", "hai", "dos", "deux", "zwo" đều được xử lý giống nhau, thì chữ ký đó sẽ phù hợp. Nhưng như hiện tại, phương thức được cung cấp hai chuỗi và coi chúng là số nguyên. Tại sao bạn lại muốn làm điều đó? Đó là một ý tưởng tồi.
jmoreno

2
@ loki2302: Bạn đã chấp nhận câu trả lời nói rằng bạn có thể ném một ngoại lệ không được kiểm tra khi chuyển rác, nhưng quan điểm của một ngôn ngữ được đánh máy mạnh là NGĂN NGỪA rác được chuyển. Có một phương thức mong đợi một chuỗi luôn là một giá trị số nguyên chỉ là một rắc rối. Ngay cả Integer.parseInt cũng không giải quyết tốt điều đó (một ngoại lệ về đầu vào NÊN được mong đợi là xấu, phương thức integer.TryParse của .Net tốt hơn nhiều, mặc dù việc thiếu tham số out của Java khiến nó hơi không thực tế).
jmoreno

3

1. Tôi nên chỉ định NumberFormatException như một phần của chữ ký của phương thức.

Tôi nghĩ vậy. Đó là một tài liệu hay.

2. Tôi nên xác định ngoại lệ đã kiểm tra của riêng mình (BadDataException), xử lý NumberFormatException bên trong phương thức và ném lại nó dưới dạng BadDataException.

Thỉnh thoảng đúng. Các trường hợp ngoại lệ đã kiểm tra được coi là tốt hơn trong một số trường hợp, nhưng làm việc với chúng là một PITA. Đó là lý do tại sao nhiều khung công tác (ví dụ: Hibernate) chỉ sử dụng ngoại lệ thời gian chạy.

3. Tôi nên xác định ngoại lệ đã kiểm tra của riêng mình (BadDataException), xác thực cả hai chuỗi theo một cách nào đó như biểu thức chính quy và ném BadDataException của tôi nếu nó không khớp.

Không bao giờ. Công việc nhiều hơn, tốc độ ít hơn (trừ khi bạn mong đợi việc ném ngoại lệ trở thành quy tắc) và không có lợi gì cả.

4. Ý tưởng của bạn?

Không có gì cả.


2

Số 4.

Tôi nghĩ rằng tôi sẽ không thay đổi phương pháp nào cả. Tôi sẽ thử nắm bắt xung quanh phương thức gọi hoặc cao hơn trong dấu vết ngăn xếp, nơi tôi đang ở trong bối cảnh nơi tôi có thể khôi phục một cách duyên dáng với logic nghiệp vụ từ ngoại lệ.

Tôi sẽ không chắc chắn làm số 3 vì tôi cho rằng nó quá mức cần thiết.


2

Giả sử rằng những gì bạn đang viết sẽ bị người khác sử dụng (như là một API), thì bạn nên sử dụng 1, NumberFormatException dành riêng cho mục đích giao tiếp các ngoại lệ như vậy và nên được sử dụng.


2
  1. Trước tiên, bạn cần phải tự hỏi bản thân của mình, liệu người dùng phương pháp của tôi có cần lo lắng về việc nhập sai dữ liệu hay không, hay liệu anh ta có nhập đúng dữ liệu không (trong trường hợp này là Chuỗi). Kỳ vọng này còn được gọi là thiết kế theo hợp đồng .

  2. và 3. Có, bạn có thể nên định nghĩa BadDataException hoặc thậm chí tốt hơn là sử dụng một số cái hay hơn như NumberFormatException nhưng để thông báo chuẩn được hiển thị. Bắt NumberFormatException trong phương thức và ném lại nó cùng với thông báo của bạn, không quên bao gồm dấu vết ngăn xếp ban đầu.

  3. Nó phụ thuộc vào tình huống mà tôi có thể sẽ sử dụng lại NumberFormatException với một số thông tin bổ sung. Và cũng phải có giải thích javadoc về các giá trị mong đợi choString a, String b


1

Phụ thuộc rất nhiều vào kịch bản bạn đang ở.

Trường hợp 1. Chính bạn luôn là người gỡ lỗi mã chứ không ai khác và ngoại lệ sẽ không gây ra trải nghiệm người dùng xấu

Ném NumberFormatException mặc định

Trường hợp 2: Mã phải cực kỳ dễ bảo trì và dễ hiểu

Xác định ngoại lệ của riêng bạn và thêm nhiều dữ liệu hơn để gỡ lỗi khi ném nó.

Bạn không cần kiểm tra regex vì dù sao thì nó cũng sẽ ngoại lệ đối với đầu vào xấu.

Nếu đó là mã cấp độ sản xuất, ý tưởng của tôi sẽ là xác định nhiều trường hợp ngoại lệ tùy chỉnh, như

  1. Ngoại lệ định dạng số
  2. Tràn ngoại lệ
  3. Ngoại lệ rỗng, v.v.

và đối phó với tất cả những điều này một cách riêng biệt


1
  1. Bạn có thể làm như vậy, để làm rõ rằng điều này có thể xảy ra nếu nhập sai. Nó có thể giúp ai đó sử dụng mã của bạn nhớ cách xử lý tình huống này. Cụ thể hơn, bạn đang nói rõ rằng bạn không tự xử lý nó trong mã hoặc trả về một số giá trị cụ thể để thay thế. Tất nhiên, JavaDoc cũng nên làm rõ điều này.
  2. Chỉ khi bạn muốn buộc người gọi đối phó với một ngoại lệ đã chọn.
  3. Điều đó có vẻ như quá mức cần thiết. Dựa vào phân tích cú pháp để phát hiện đầu vào không hợp lệ.

Nói chung, một NumberFormaException được bỏ chọn vì dự kiến ​​rằng đầu vào có thể phân tích cú pháp chính xác được cung cấp. Xác thực đầu vào là điều bạn nên xử lý. Tuy nhiên, thực sự phân tích cú pháp đầu vào là cách dễ nhất để làm điều này. Bạn chỉ cần để nguyên phương thức của mình và cảnh báo trong tài liệu rằng mong đợi đầu vào chính xác và bất kỳ ai gọi hàm của bạn nên xác thực cả hai đầu vào trước khi sử dụng nó.


1

Bất kỳ hành vi ngoại lệ nào cần được làm rõ trong tài liệu. Hoặc nó phải nêu rõ rằng phương thức này trả về một giá trị đặc biệt trong trường hợp không thành công (như null, bằng cách thay đổi kiểu trả về thành Integer) hoặc trường hợp 1 nên được sử dụng. Có nó rõ ràng trong chữ ký của phương thức cho phép người dùng bỏ qua nó nếu anh ta đảm bảo các chuỗi chính xác bằng cách khác, nhưng rõ ràng là phương thức không tự xử lý loại lỗi này.


1

Câu trả lời cho câu hỏi cập nhật của bạn.

Vâng, hoàn toàn bình thường khi có những ngoại lệ "bất ngờ". Hãy nghĩ về tất cả các lỗi thời gian chạy mà người ta mắc phải khi mới lập trình.

e.g ArrayIndexOutofBound

Cũng là một ngoại lệ bất ngờ phổ biến từ vòng lặp cho mỗi.

ConcurrentModificationException or something like that

1

Mặc dù tôi đồng ý với câu trả lời rằng ngoại lệ thời gian chạy nên được phép tô màu, từ góc độ thiết kế và khả năng sử dụng, sẽ là một ý tưởng hay nếu gói nó thành IllegalArgumentException thay vì ném nó dưới dạng NumberFormatException. Điều này sau đó làm cho hợp đồng của phương thức của bạn rõ ràng hơn, theo đó nó tuyên bố một đối số bất hợp pháp đã được chuyển cho nó do đó nó ném ra một ngoại lệ.

Về bản cập nhật cho câu hỏi "Hãy tưởng tượng, nó không phải là một khuôn khổ nguồn mở, mà bạn nên sử dụng vì một số lý do. Bạn nhìn vào chữ ký của phương thức và nghĩ -" OK, nó không bao giờ ném ". Sau đó, một ngày nào đó, bạn có một ngoại lệ . Nó có bình thường không?" javadoc của phương thức của bạn phải luôn tràn ra hành vi của phương thức của bạn (các ràng buộc trước và sau). Hãy nghĩ về các dòng giao diện bộ sưu tập giả sử trong đó nếu không cho phép null, javadoc nói rằng một ngoại lệ con trỏ null sẽ được ném ra mặc dù nó không bao giờ là một phần của chữ ký phương thức.


2
NumberFormatException là một lớp con của IllegalArgumentException, vì vậy gói này không thêm thông tin.
Don Roby

điều đó có nghĩa là ngoại lệ có thể được ghép lại như cũ (như trong trường hợp này nfe đã là một ngoại lệ đối số bất hợp pháp) và có thể có một xử lý chung để đối phó với các đối số bất hợp pháp ở đâu đó trong hệ thống phân cấp cuộc gọi. vì vậy nếu đây là một ví dụ trong đó các đối số được chuyển bởi người dùng, có thể có một mã chung sẽ bao gồm tất cả các xử lý đối với các đối số bất hợp pháp và thông báo cho người dùng về nó.
Scorpion

1

Như bạn đang nói về thực hành java tốt, theo tôi nó luôn tốt hơn

  • Để xử lý ngoại lệ không được chọn, sau đó phân tích nó và thông qua một ngoại lệ không được chọn tùy chỉnh.

  • Ngoài ra trong khi ném ngoại lệ không được chọn tùy chỉnh, bạn có thể thêm thông báo Ngoại lệ mà khách hàng của bạn có thể hiểu và cũng in dấu vết ngăn xếp của ngoại lệ ban đầu

  • Không cần phải khai báo ngoại lệ tùy chỉnh là "ném" vì nó không được chọn.

  • Bằng cách này, bạn sẽ không vi phạm việc sử dụng các ngoại lệ không được kiểm tra nào được tạo ra, đồng thời ứng dụng khách của mã sẽ dễ dàng hiểu lý do và giải pháp cho ngoại lệ.

  • Ngoài ra việc ghi lại tài liệu đúng cách trong java-doc cũng là một phương pháp hay và giúp ích rất nhiều.


1

Tôi nghĩ nó phụ thuộc vào mục đích của bạn, nhưng tôi sẽ ghi lại nó ở mức tối thiểu:

/**
 * @return the sum (as an int) of the two strings
 * @throws NumberFormatException if either string can't be converted to an Integer
 */
public static int sum(String a, String b)
  int x = Integer.parseInt(a);
  int y = Integer.parseInt(b);
  return x + y;
}

Hoặc, lấy một trang từ mã nguồn Java cho lớp java.lang.Integer:

public static int parseInt(java.lang.String string) throws java.lang.NumberFormatException;

1

Còn về mẫu xác thực đầu vào được thực hiện bởi thư viện 'Guava' của Google hoặc thư viện 'Trình xác thực ' của Apache ( so sánh )?

Theo kinh nghiệm của tôi, việc xác thực các tham số của một hàm ở phần đầu của hàm được coi là phương pháp hay và ném các Ngoại lệ khi thích hợp.

Ngoài ra, tôi sẽ coi câu hỏi này phần lớn là độc lập về ngôn ngữ. 'Thực hành tốt' ở đây sẽ áp dụng cho tất cả các ngôn ngữ có các hàm có thể nhận các tham số có thể có hoặc có thể không hợp lệ.


1

Tôi nghĩ câu đầu tiên của bạn về "Một câu hỏi ngu ngốc" rất phù hợp. Tại sao bạn lại viết một phương thức với chữ ký đó ngay từ đầu? Nó thậm chí có ý nghĩa để tính tổng hai chuỗi? Nếu phương thức gọi muốn tính tổng hai chuỗi, trách nhiệm của phương thức gọi là đảm bảo chúng là các int hợp lệ và chuyển đổi chúng trước khi gọi phương thức.

Trong ví dụ này, nếu phương thức gọi không thể chuyển đổi hai Chuỗi thành một int, nó có thể thực hiện một số việc. Nó thực sự phụ thuộc vào lớp mà tổng kết này xảy ra ở. Tôi giả định rằng chuyển đổi Chuỗi sẽ rất gần với mã giao diện người dùng (nếu nó được thực hiện đúng cách), chẳng hạn như trường hợp 1. sẽ có nhiều khả năng:

  1. Đặt thông báo lỗi và ngừng xử lý hoặc chuyển hướng đến trang lỗi
  2. Trả về false (tức là, nó sẽ đưa tổng vào một số đối tượng khác và không bắt buộc phải trả lại)
  3. Hãy ném một số BadDataException như bạn đang đề xuất, nhưng trừ khi tổng của hai số này là rất quan trọng, điều này là quá mức cần thiết và giống như đã đề cập ở trên, đây có thể là thiết kế tồi vì nó ngụ ý rằng việc chuyển đổi đang được thực hiện không đúng chỗ.

1

Có rất nhiều câu trả lời thú vị cho câu hỏi này. Nhưng tôi vẫn muốn thêm điều này:

Để phân tích cú pháp chuỗi, tôi luôn thích sử dụng "biểu thức chính quy". Gói java.util.regex ở đó để giúp chúng tôi. Vì vậy, tôi sẽ kết thúc với một cái gì đó như thế này, không bao giờ ném bất kỳ ngoại lệ nào. Tôi tùy thuộc vào việc trả về một giá trị đặc biệt nếu tôi muốn gặp một số lỗi:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public static int sum(String a, String b) {
  final String REGEX = "\\d"; // a single digit
  Pattern pattern = Pattern.compile(REGEX);
  Matcher matcher = pattern.matcher(a);
  if (matcher.find()) { x = Integer.matcher.group(); }
  Matcher matcher = pattern.matcher(b);
  if (matcher.find()) { y = Integer.matcher.group(); }
  return x + y;
}

Như mọi người có thể thấy, mã chỉ dài hơn một chút, nhưng chúng ta có thể xử lý những gì chúng ta muốn (và đặt giá trị mặc định cho x và y, kiểm soát những gì xảy ra với các mệnh đề khác, v.v.) Chúng ta thậm chí có thể viết một phép biến đổi tổng quát hơn quy trình mà chúng ta có thể chuyển chuỗi, giá trị trả về mặc định, mã REGEX để biên dịch, thông báo lỗi để ném, ...

Hy vọng nó là hữu ích.

Cảnh báo: Tôi không thể kiểm tra mã này, vì vậy vui lòng bỏ qua các vấn đề cú pháp cuối cùng.


1
chúng ta đang nói về Java? Là Integer.matchergì? privatebiến bên trong phương thức? Thiếu ()cho IFS, thiếu rất nhiều ;, x, ykhông khai báo, matchertuyên bố hai lần, ...
user85421

Thật vậy, Carlos, tôi đã làm điều đó một cách vội vàng, và như tôi đã nói, không thể kiểm tra nó ngay lập tức. Lấy làm tiếc. Tôi muốn chỉ ra cách làm của regex.
Louis

OK, nhưng điều này không giải quyết vấn đề với NumberFormatException - câu hỏi chính IMO - (giả định rằng Integer.matcher.group()có nghĩa là để được Integer.parseInt(matcher.group()))
user85421

0

Bạn phải đối mặt với vấn đề này vì bạn đã để lỗi người dùng lan truyền quá sâu vào cốt lõi của ứng dụng và một phần cũng do bạn lạm dụng kiểu dữ liệu Java.

Bạn nên tách biệt rõ ràng hơn giữa xác thực đầu vào của người dùng và logic nghiệp vụ, sử dụng cách nhập dữ liệu thích hợp và vấn đề này sẽ tự biến mất.

Thực tế là ngữ nghĩa của đã Integer.parseInt()được biết đến - mục đích chính của nó là phân tích cú pháp các số nguyên hợp lệ . Bạn đang thiếu bước xác thực / phân tích cú pháp đầu vào của người dùng rõ ràng.

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.