2011-01-17 30 views
5

Dường như không phải là một ý tưởng hay để bắt được một nhận dạng nullpointerexception. Nếu đó là trường hợp, tại sao nó được ném bằng phương pháp? Nếu nó chỉ bị bắt với ngoại lệ?Thực hành tốt nhất trong đánh bắt và ném nullpointerexception?

Ngoài ra, nếu tôi gặp phải tham số rỗng (có thể là kiểu nguyên thủy như chuỗi hoặc lớp có trường), tôi nên xử lý nó như thế nào? (giả sử không ném npe)?

Cảm ơn

+3

Chuỗi không phải là loại nguyên thủy, fyi. – fmucar

+1

Chuỗi có thể là null, nhưng một kiểu nguyên thủy như 'int' không thể. –

+1

Nó được ném bởi các phương thức bởi vì ai đó (đọc: bạn) đang chuyển các giá trị null cho nó. Tốt nhất bạn nên tránh null vào mọi lúc, và/hoặc phân tán ứng dụng của bạn bằng các kiểm tra rỗng. Thích sử dụng các chuỗi rỗng, mẫu đối tượng Null và ngược lại. – fwielstra

Trả lời

6

Một nhận dạng con trỏ không thường chỉ ra một programmer error. Bạn sẽ không bắt được một ngoại lệ con trỏ null nếu bạn không mong đợi một lỗi lập trình như vậy. Ví dụ: giả sử bạn triển khai phương thức myMethod với một tham số thuộc loại P.

void myMethod(P x) 

Giả sử bạn không mong đợi tham số x là rỗng. Trong trường hợp này bạn có thể không kiểm tra null. Tại sao? bởi vì bạn cho rằng lập trình viên đang sử dụng phương thức của bạn sẽ sử dụng nó đúng cách và sẽ không vượt qua null. Tôi không nói bạn nên hay không nên kiểm tra null trong những trường hợp như vậy. Tôi chỉ cố gắng để trả lời tại sao đôi khi một ngoại lệ con trỏ null được ném bởi một phương pháp và không phải là nghĩa vụ phải bị bắt. Đây là lý do tại sao: Phương pháp của bạn có thể ném một ngoại lệ con trỏ null bởi vì ai đó đã không sử dụng nó đúng (thông qua null). Các lập trình viên đang sử dụng phương pháp của bạn có thể biết rằng nếu phương pháp đang được sử dụng sai nó có thể ném một nullpointerexcetption. Nhưng ngay cả khi anh ta sử dụng phương pháp của bạn sai thì ngoại lệ sẽ không bị bắt vì mọi người đều cho rằng phương pháp này không bị lạm dụng.

Câu hỏi thứ hai của bạn: Thứ nhất, một Chuỗi là một đối tượng, không phải là kiểu nguyên thủy. Thứ hai, nguyên thủy không thể được null (nguyên thủy là ints, tăng gấp đôi, nổi, ký tự, booleans và một số người khác). Bây giờ, nếu bạn gặp một thông số mà là null và nó không nên được null (nói cách khác bạn nhận được một cuộc tranh cãi bất hợp pháp), bạn có một số lựa chọn:

  • Ném một IllegalArgumentException chỉ ra tham số là null và phương pháp của bạn hy vọng nó không được rỗng.
  • Đừng làm gì cả. Giả sử phương pháp của bạn đang được sử dụng đúng cách (nói cách khác, giả sử không có lỗi lập trình viên).
  • Sử dụng assertions: assert(x != null);

Cá nhân tôi không phải là một fan hâm mộ của defensive programming và thường thích lựa chọn thứ hai. Nhưng vẫn còn, nếu tôi muốn đảm bảo một số bất biến trên các biến của tôi, tôi đang sử dụng các xác nhận. Nhưng đây chỉ là thói quen của tôi và những người khác có thể không đồng ý.

+0

Lưu ý rằng đôi khi được coi là thực hành tốt hoặc tốt hơn để ném NPE thay vì IllegalArgumentException trong trường hợp đối số rỗng. Nhưng đó có lẽ là một đối số của sở thích cá nhân - một null cũng có thể được coi là một đối số bất hợp pháp. – fwielstra

14

Nó là một ngoại lệ runtime, do đó không có ý định để bị bắt sâu bên trong mã chương trình của bạn, chỉ [cập nhật] tại (hoặc gần) cấp cao nhất hoặc [/ cập nhật ] bởi JVM. Vì các ngoại lệ thời gian chạy báo hiệu các vấn đề nghiêm trọng (thường là lỗi lập trình nghiêm trọng, các vấn đề về cấu hình/tích hợp, v.v.), tốt nhất là để chúng lan truyền lên đầu, thường làm cho toàn bộ luồng không thành công một cách ngoạn mục. Điều này cho thấy một tín hiệu mạnh mẽ rằng một cái gì đó là sai và cần phải được cố định càng sớm càng tốt.

Xem thêm Is Catching a Null Pointer Exception a Code Smell?.

Ngoài ra, nếu tôi gặp thông số rỗng [...], tôi nên xử lý thông số như thế nào?

Bạn có thể ném NPE nói chung. Tuy nhiên, tùy thuộc vào hoàn cảnh, bạn cũng có thể xem xét IllegalArgumentException hoặc using an assertion. Xem thêm

+1

+1 Tuy nhiên, tôi nghĩ câu lệnh rằng các ngoại lệ thời gian chạy không có ý định bị bắt trong mã chương trình là chủ quan sai. Khái niệm về một rào cản lỗi tồn tại đặc biệt để bảo vệ người dùng hàng ngày không nhìn thấy một stacktrace. –

+0

@Tim, bạn nói đúng, tôi đã cẩu thả với điều này. Tôi đã sửa văn bản ở trên. Cảm ơn :-) –

1

NPERuntimeException s nói chung chủ yếu ném khi có một lỗi mã hóa, đó là lý do tại sao bắt họ không được coi là một ý tưởng tốt. Những gì nên được thực hiện thay vì sửa chữa mã mà không thể xử lý đầu vào null.

Đây là phần thứ hai của câu hỏi của bạn, cách xử lý đầu vào rỗng. Nó phụ thuộc hoàn toàn vào những gì bạn đang mong đợi hợp lý trong mã của bạn. Giả sử bạn đọc dữ liệu từ một bảng cơ sở dữ liệu và đọc một giá trị null từ cột có thể rỗng, điều đó chắc chắn không phải là một trường hợp ngoại lệ, vì vậy mã của bạn nên xử lý nó như là sự thích hợp của nó từ một quan điểm kinh doanh (vd bỏ qua toàn bộ hàng, nhắc người dùng nhập giá trị hoặc chỉ sử dụng giá trị giả). Tuy nhiên nếu bạn đang đọc một giá trị null từ một cột không nullable, nói một khóa chính, bạn nên ném một ngoại lệ cho ứng dụng cụ thể, (hy vọng) được xử lý bởi giao diện người dùng của ứng dụng của bạn. Vì vậy, câu trả lời thực sự đơn giản như: nếu null là một giá trị có thể xảy ra trong quá trình hoạt động bình thường, hãy xử lý nó tương ứng, nếu không, hãy ném ngoại lệ doanh nghiệp đã kiểm tra thay vì NPE.

+1

Ngoài ra, nếu "đầu vào rỗng" đề cập đến các đối số null được truyền vào một phương thức không mong đợi chúng được vô hiệu, thì một NPE là thích hợp; xem 'Precondition.checkNotNull' của ổi. Thực tiễn tốt là làm như vậy trong các API công khai vì nó ngay lập tức hiển thị cho lập trình viên rằng họ đã sử dụng API không chính xác. – ide

+0

Đúng, nếu bạn đang viết thư viện của bên thứ ba, việc ném NPE có thể thích hợp, tôi đã tập trung vào mã "người dùng cuối". – biziclop

1

Trường hợp có thể xảy ra nhất mà bạn có thể muốn bắt NPE là khi bạn triển khai một loại khung, nghĩa là bạn KHÔNG muốn chấm dứt đơn đăng ký của mình, nhưng báo cáo lỗi và bạn có cách (hợp lý) tiếp tục trong đơn của bạn.

2

Ném IllegalArgumentException thay vì NP nếu có ai đó chuyển Null bất hợp pháp vào phương thức của bạn. Điều đó mô tả tốt hơn lỗi.

0

Để tránh kiểm tra null trong mã của bạn, trong hầu hết các trường hợp, nó thích hợp để trả về một đối tượng rỗng hoặc danh sách/bản đồ/bộ trống thay vì null.

3

Câu trả lời này có thể dài nhưng tôi nghĩ nó đáng giá.

Dường như không có ý tưởng hay để nắm bắt một nhận dạng nullpointerexception.

Bạn nói đúng, bạn không nên bắt NullPointerException, cũng như bất kỳ ngoại lệ thời gian chạy nào.

Nếu trường hợp đó xảy ra, tại sao nó được phương pháp đưa ra? Nếu nó chỉ bị bắt với ngoại lệ?

Nó được sử dụng để chỉ ra lỗi lập trình đã được tìm thấy.Các lỗi lập trình này có thể và phải được sửa bằng mã (Có nghĩa là chúng có thể ngăn ngừa được)

Ngoài ra, nếu tôi gặp phải tham số rỗng cách xử lý? [...] (giả sử không ném npe)?

Tùy thuộc vào những gì bạn muốn làm. Đối với một số logic, giá trị null có thể được cho phép. Nếu đó là trường hợp, bạn xác nhận sự hiện diện của null và làm một cái gì đó về nó, hoặc là cung cấp một giá trị mặc định hoặc tránh gửi messaged đến null.

Ví dụ: Giả sử bạn có hệ thống thông tin thanh toán và bạn có mã này nơi bạn lưu thông tin khách hàng và bạn có thể tùy ý lưu thông tin bổ sung của khách hàng.

Trong trường hợp này, thông báo tùy chọn có thể là rỗng và mã của bạn phải xác thực sự hiện diện của nó.

Ví dụ:

/** 
* ... 
* @param - OptionalMessage may be null, include anything else you wan to save. 
*/ 
public void sendCustomerInformation(Customer c , OptionalMessage optionalMessage) { 
    SomeMessage message = SomeMessage.createMessage(); 
    message.setHeader(c.name()); 
    message.setCustomerInformation(c); 
    if(optionalMessage != null) { // is optional? handle it 
     message.add(optionalMessage.status()); 
     message.add(optionalMessage.summary()); 
     message.add(optionalMessage.message()); 
    } 
} 

}

Bạn xác nhận sự hiện diện của vô tài liệu đó.

Nhưng mã này cùng cũng có một khách hàng như tham số, trong trường hợp này bạn có thể:

a) Không làm gì b) Validate nó cũng c) Ném một ngoại lệ khác nhau tùy theo mức độ trừu tượng ở cấp độ này.

Ví dụ: mã trên, không a) không có gì. Điều này sẽ dẫn đến một NullPointerException nơi mã số c.name() được gọi, và điều này sẽ được nắm bắt sớm trong các bài kiểm tra phát triển. Ngoài ra, nó nên được ghi lại, trong param và ném trong javadoc.

/** 
* ... 
* @param c - The customer whose information is to be sent. NotNull 
* ... 
* @throws NullPointerException if the customer is null 
*/ 
public void sendCustomerInformation(Customer c , OptionalMessage optionalMessage) { 
    SomeMessage message = SomeMessage.createMessage(); 
    ... 

Nếu ai đó gọi phương thức này bằng không, thì Npe sẽ cho biết họ đã mã hóa điều gì đó sai. Thêm vào đó, Npe, sẽ nói rất nhanh những gì và nơi các lỗi mã hóa được (khi gọi sendCustomerInformation với khách hàng null.

tùy chọn b) Xác nhận nó. Nó có thể là trường hợp, khi bạn có thể cho phép xử lý một khách hàng rỗng (nó không có ý nghĩa nhưng, nó là một tùy chọn)

Trong trường hợp này bạn có thể xác nhận nó và trả lại sớm (trong I) đang thực hiện thời trang)

public void sendCustomerInformation(Customer c , OptionalMessage optionalMessage) { 
    if(cusomer == null) { return; // I'm done! } 
    // else 
    SomeMessage message = ... 
    .. 
} 

Hoặc có thể tạo ra một sự thay thế:

public void sendCustomerInformation(Customer c , OptionalMessage optionalMessage) { 
    if(cusomer == null) { c = new EmptyCustomer() ;} 
    // else 
    SomeMessage message = ... 
    .. 
} 

tùy chọn c) này cũng tương tự như vậy, nhưng, trong trường hợp này bạn ném ngoại lệ theo mức độ trừu tượng.Ví dụ, nếu điều này sẽ được hiển thị cho người sử dụng cuối cùng trong một giao diện hoặc một cái gì đó, nó có thể không có ý nghĩa để chỉ ném NPE:

public void sendCustomerInformation(Customer c , OptionalMessage optionalMessage) { 
    if(cusomer == null) { 
    // oh oh something went wrong. 
    log.fatal("Invalid argument on \"sendCustomerInformation\"); 
    throw new MyApplicationException("Dear customer, the information yada yaa"); 
    } 
    ... 

Nếu đây là một số loại nhà nước invalida trong ứng dụng:

public void sendCustomerInformation(Customer c , OptionalMessage optionalMessage) { 
    if(cusomer == null) { 
    // wait a minute, how could... why did.. what? 
    throw new IllegalStateException("Hey, I got null on sendCustomerInformation and this shouldn't happen"); 
    } 
    ... 

Vì có thể ứng dụng chịu trách nhiệm giữ đối tượng/thông số đó ở dạng hợp lệ.

Kết luận

Vì vậy, nó phụ thuộc vào kịch bản, nhưng về tổng quát, một NullPointerException (và hầu hết RuntimeExceptions) cho thấy một cái gì đó mà có thể được cố định với mã (đó là một sai lầm lập trình viên) và bạn luôn có thể làm một cái gì đó về nó. Có những trường hợp bạn không thể làm điều gì đó về nó, điều tốt nhất bạn có thể làm là để cho nó bật lên.

Tôi hy vọng điều này sẽ hữu ích.

Xem thêm: Exception other than RuntimeException

+0

Đây là câu trả lời rất tốt. Cảm ơn! – dotnetdev

+1

@dotnetdev Tôi rất vui vì nó đã giúp ích. Bạn có thể xem xét đánh dấu là đã chấp nhận: ") – OscarRyz

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