2013-05-07 31 views
23

Tôi thấy rằng trong Java 7, họ đã giới thiệu phương pháp Objects.requireNonNull(T obj, String message).Java 7 Constructor

Kiểm tra tham chiếu đối tượng được chỉ định không phải là rỗng và ném tùy chỉnh NullPointerException nếu có. Phương pháp này được thiết kế chủ yếu để thực hiện xác thực tham số trong các phương thức và hàm tạo với nhiều tham số.

Trước khi bắt đầu định dạng lại mã của mình, tôi sẽ yêu cầu ở đây để có một số phản hồi về việc sử dụng mã đó.

public Foo(Bar bar, Baz baz) { 
     /** Old one 
     this.bar = bar; 
     this.baz = baz; 
     **/ 
     this.bar = Objects.requireNonNull(bar, "bar must not be null"); 
     this.baz = Objects.requireNonNull(baz, "baz must not be null"); 
    } 

Thực tiễn tốt hơn là sử dụng nó trực tiếp khi tôi xây dựng đối tượng (Tôi đang nghĩ về việc tạo thư viện hoặc các công cụ khác cho nhà phát triển)?

Hoặc tôi có nên để nó làm công cụ xây dựng "cổ điển/cũ" không?

+0

Điều đó tùy thuộc. Bạn có muốn một ngoại lệ ném vào constructor của bạn? – Reimeus

+0

Trên thực tế, nếu ngoại lệ không được ném vào hàm tạo, nó chắc chắn sẽ bị ném bằng cách gọi các phương thức của lớp này. Mục đích của việc này là: tôi nên trực tiếp ngăn người dùng xây dựng ("Hãy cẩn thận một số đối tượng là null, do đó bạn sẽ không thể thực hiện một số phương thức") hoặc tôi để anh ta ném ngoại lệ này (nếu anh ta gọi một số phương pháp của lớp)? – user2336315

+0

Tôi đã sử dụng mẫu Builder ở đây và, như Ravi đề xuất dưới đây, ném IllegalArgumentException (hoặc IllegalStateException.) – Marvo

Trả lời

11

Như bạn có thể thấy, có sự không đồng ý cho dù một NPE hoặc một số ngoại lệ khác phải được ném .

Nếu bạn chấp nhận rằng một NPE là thích hợp hơn so với các lựa chọn thay thế, và đây là một tình huống mà null là dứt khoát không chính xác, sau đó:

  • nó là tốt hơn để ném NPE sớm; tức là trong nhà xây dựng và
  • thì tốt hơn là hãy ném nó bằng thông báo ngoại lệ tùy chỉnh; tức là không phải là null như xảy ra khi JVM ném NPE.

Trong ngữ cảnh đó sử dụng Objects.requireNonNull là thực tế tốt.


Bạn cũng có thể sử dụng khẳng định Java cho điều này, nhưng bạn cần phải thực hiện một phán quyết về việc liệu nó là một điều tốt hay xấu mà các thử nghiệm thể được tắt. Bạn phải xem xét liệu lợi ích hiệu suất của việc bật kiểm tra sớm có vượt quá những vấn đề có thể xảy ra do không kiểm tra trước đó hay không. Ví dụ, giả sử bạn thấy một NPE trong sản xuất với các xác nhận bị tắt ... và bạn không thể chẩn đoán nó. Bạn có bật xác nhận không? Các xác nhận có thay đổi hành vi của mã không? Nó sẽ làm chậm hệ thống của bạn xuống (do rất nhiều kiểm tra xác nhận khác)? Tình huống đã kích hoạt NPE có khả năng tái diễn?

(lỗi liên quan đến luồng thường là "một lần trong mặt trăng xanh" những thứ cực kỳ khó tái tạo. Tôi cho rằng bạn cần thông tin để chẩn đoán sự cố BẤT K time thời gian xảy ra ... không chỉ khi bạn đã bật tính năng kiểm tra xác nhận.)


Đối số tương thích ngược có thể có liên quan. Tuy nhiên, theo nguyên tắc chung, bạn không viết mã của mình để chạy trên các nền tảng Java cũ. Nếu bạn có yêu cầu cụ thể để hỗ trợ các phiên bản Java cũ ... thì điều đó khác. Nhưng nếu đó là trường hợp, bạn không nên làm phát triển của bạn chống lại các API Java 7 ở tất cả ... do đó trình biên dịch/IDE của bạn nên gắn cờ các lớp Objects là lỗi biên dịch.

(Hạn chế bản thân chỉ sử dụng các API cũ hơn khi bạn không cần phải làm cho chất lượng mã của bạn bị ảnh hưởng và làm cho nó "lỗi thời" trước đó. dễ dàng hơn để viết đáng tin cậy/ứng dụng duy trì Cố ý không sử dụng nó là ... ngoan cố Hãy tưởng tượng nếu bạn hạn chế bản thân để Java 1.1 ...)


1 -.. FWIW, tôi nghĩ NPE của là tốt. Và NPE với thông điệp cụ thể hơn (nói) IllegalArgumentException và có rất nhiều tiền lệ trong thư viện lớp chuẩn Java cho các nhà xây dựng, v.v ... được ghi lại khi ném NPE. Bên cạnh đó, phương pháp này được thiết kế rõ ràng để sử dụng theo cách này.

+0

+1 .. và như tôi đã nói với @Ravi .. cũng nghĩ rằng NPE tốt hơn (cụ thể hơn) so với IllegalArgumentException (hoặc IStateExc) – joaonlima

+0

'Liệu nó có làm chậm hệ thống của bạn xuống (do nhiều kiểm tra xác nhận khác) không? vì bạn có thể bật xác nhận chọn lọc chỉ cho một gói chẳng hạn. –

+0

@Ravi - chỉ khi bạn biết gói nào chứa lớp chứa 'khẳng định' sẽ bắt được sự cố. Và thậm chí sau đó, có thể có ** kiểm tra ** assert' đắt tiền hơn trong lớp/gói/bất cứ điều gì mà bạn đã chọn bật xác nhận cho. –

0

Nếu bạn tình cờ có setters cho barbaz, bạn nên làm điều đó trong setters:

public Foo(Bar bar, Baz baz) { 
    setBar(bar); 
    setBaz(baz); 
} 

public void setBar(Bar bar) { 
    this.bar = Objects.requireNonNull(bar, "bar must not be null"); 
} 

public void setBaz(Baz baz) { 
    this.baz = Objects.requireNonNull(baz, "baz must not be null"); 
} 

Nếu phương pháp mà bạn thấy là tốt.

Về câu hỏi về làm việc đó ở tất cả - nếu đối tượng của bạn là hoàn toàn vô ích khi barbaz là null, bạn cũng có thể thực hiện kiểm tra null tại các nhà xây dựng & setters. Nhưng nếu đối tượng của bạn có thể được sử dụng khi chúng là null - ngay cả khi việc sử dụng đó chỉ là kiểm tra xem chúng có rỗng hay không và đặt chúng bằng setter, giả sử đó là cách sử dụng hợp pháp lớp của bạn - thì bạn có thể cho phép người dùng của bạn làm điều đó.

9

Tôi không cảm thấy thoải mái với thực tế là requireNonNull() ném một NullPointerException. Theo ý kiến ​​của tôi, việc ném cổ điển IllegalArgumentException làm cho ý định rõ ràng hơn. Người ta cũng có thể sử dụng Assertions cùng với lợi thế là chúng có thể được bật và tắt một cách có chọn lọc.

Trên đầu trang của nó, nếu bạn muốn để lộ mã của bạn như là một thư viện nên thường nỗ lực để hỗ trợ JDK lâu đời nhất có thể.

EDIT: Tôi muốn thêm rằng chọn bất kỳ khung nổi tiếng nào hôm nay và bạn sẽ thấy rằng các API của họ sẽ luôn ném ngoại lệ với các tên như vậy mô tả bạn gần như ngay lập tức nhận biết điều gì là sai.

Để đưa ra một ví dụ, điều gì sẽ xảy ra khi một thùng chứa Spring phát hiện rằng thuộc tính @Required trên bean được quản lý không thể được tiêm và do đó vẫn giữ nguyên là NULL. Bạn chắc chắn không nhận được NullPointerException với mô tả thông báo lỗi nhất có thể.

Bạn nhận được một BeanCreationException quấn quanh một BeanInitializationException cho biết thêm thông tin về các biến thành viên đó vẫn là null trong một tin nhắn đủ lỗi mô tả như sau: 'trung tâm' tài sản là cần thiết cho đậu 'vòng tròn'.

+0

Tôi không đồng ý .. NullPointerException, theo ý kiến ​​của tôi, phù hợp hơn trong trường hợp này bởi vì nó nêu rõ rằng vấn đề là một 'null' được truyền qua nơi nó không thể (vì chúng ta có một thông điệp). Một IllegalArgument có thể được sản xuất bởi bất cứ điều gì sai, các đối số nên lớn hơn 0, giá trị nên được serializable, vv – joaonlima

+1

Có, nó đun sôi xuống một chút để sở thích. Nhưng, cá nhân tôi không nghĩ rằng mã thư viện của tôi sẽ tạo ra nhiều sự tự tin nếu nó bắt đầu ném NullPointerExceptions. Các ngữ nghĩa mặc định mà bất kỳ lập trình Java nào liên kết với nó là có một lỗi trong mã; * cái gì đó bị hỏng *. Tôi muốn ở càng xa càng tốt. –

+2

@Ravi - Nhiều lớp trong bộ sưu tập tiêu chuẩn tạo ra các NPE khi được gọi với các đối số 'null', cũng như nhiều lớp tiêu chuẩn khác. Điều đó có làm cho << bạn << cảm thấy kém tự tin hơn không? Chắc chắn, mã lỗi thường tạo ra NPE, nhưng nó không phải là hợp lý để làm cho suy luận ngược lại ... đặc biệt là nếu bạn * tài liệu * các trường hợp trong đó NPEs có thể được mong đợi. Nếu ai đó giả định rằng một NPE có nghĩa là mã của bạn là lỗi, họ là kẻ ngốc. –