2012-06-03 31 views
5

Nếu tôi đã có những chức năng dưới đây, với hai lựa chọnNém một ngoại lệ hoặc trả về null

private MyObject findBlank() { 
    for (int i = 0; i < pieces.length; i++) { 
     if(pieces[i].isBlank()){ 
      return pieces[i]; 
     } 
    } 
    return null; 
} 

private MyObject findBlank() { 
    for (int i = 0; i < pieces.length; i++) { 
     if(pieces[i].isBlank()){ 
      return pieces[i]; 
     } 
    } 
    throw new NoSuchFieldError("No blank piece found!"); 
} 

Từ phương pháp này, tôi biết rằng nó nên luôn trả về một đối tượng một trong những 'mảnh' luôn luôn là isBlank() == true, null trả về ở cuối là chỉ để làm hài lòng trình biên dịch. Vì đây là trường hợp và mã của tôi sẽ không hoạt động anyway nếu nó trả về null, đây có phải là chính xác xin vui lòng để ném một ngoại lệ?

lựa chọn của tôi là:

  1. trở lại null và ứng dụng sẽ nhận được một NullPointerException trong một số trường hợp cạnh
  2. trở lại vô quấn việc sử dụng phương pháp này với kiểm tra
  3. (myObject = null!) ném một ngoại lệ sẽ phát nổ khi chạy

Tôi đoán điều tôi đang hỏi là, đây có phải là địa điểm chính xác để ném ngoại lệ không? tức là tôi không thể làm gì nếu nó rơi vào tình huống. Điều này được phân loại là 'ngoại lệ' hay tôi không nên kiểm tra xem phương thức của tôi trả về (cái gì làm cho mã của tôi trông khủng khiếp). Nếu tôi biết nó không nên trả về null thì tôi nên ném ngoại lệ phải không?

Tôi cũng làm cách nào để chọn ngoại lệ, hoặc mở rộng một và ném của riêng mình?

+0

Để giúp chọn ngoại lệ: http://wuhrr.wordpress.com/2007/11/22/java-exceptions-list/ – Blundell

+0

Đề xuất "không" có hấp dẫn không? :-) – missingfaktor

+0

@missingfaktor Tôi đang viết mã trong Android nên không thể mang theo các khung công tác nặng khác – Blundell

Trả lời

4

Về lựa chọn của bạn, hãy tự hỏi nếu

  1. có phải là một ý tưởng tốt để có chương trình của bạn nổ tung tại một số điểm sau khi phương pháp này trả lại một giá trị bất ngờ (ví dụ: null)?
  2. Chính xác điều gì sẽ bị ẩn nếu bạn che dấu giá trị trả về null?
  3. Bạn có nên thổi phồng ngay lập tức, chỉ vì có giá trị sai?

Cá nhân tôi chọn tùy chọn 2 hoặc 3, tùy thuộc vào việc tôi có thích câu trả lời cho câu hỏi 2 hoặc 3 hay hơn không. Tùy chọn 1 chắc chắn là một ý tưởng tồi, đặc biệt là nếu nó không phải xảy ra. Nếu chương trình ném một cách NPE sau khi hàm của bạn quay trở lại, bạn sẽ gặp khó khăn trong việc tìm ra nơi mà null xuất phát từ đó. Đặc biệt là nếu nó xảy ra vài tháng sau khi bạn hoàn thành công việc trên chức năng cụ thể này.

Nếu bạn chọn để ném một ngoại lệ, bạn ngay lập tức nhìn thấy nơi một cái gì đó đã đi sai và bạn có thể trực tiếp đến đó để tìm ra lý do tại sao nó đã đi sai. Quay trở lại null và kiểm tra nó trong chức năng gọi cũng có thể hoạt động, nhưng chỉ khi bạn không thất bại, nhưng thực sự làm một cái gì đó để xử lý vấn đề đúng cách.

4

Có, bạn nên ném RuntimeException để cho biết tình huống "ngoại lệ" không nên xảy ra. IllegalStateException có thể phù hợp với hóa đơn. Hãy chắc chắn bao gồm một tin nhắn với bất kỳ thông tin nào sẽ giúp bạn tìm ra lỗi nếu nó đã từng bị ném.

+0

Tôi không chắc mình đồng ý với phần "không thể khôi phục". –

+0

@HovercraftFullOfEels - Bạn khuyên bạn nên nói như thế nào? –

+0

Tôi sẽ xóa phần "mà từ đó chương trình của bạn không thể khôi phục". –

10

Tôi đoán điều tôi đang hỏi là, đây có phải là địa điểm chính xác để ném ngoại lệ không?

Nếu đó là tình huống đặc biệt đặc biệt thì có. Nếu khả năng không tìm thấy bất kỳ điều gì phù hợp với tiêu chí là được mong đợi thì tình huống không phải là đặc biệt và bạn phải trả lại null.

0

nên luôn trả về một đối tượng hoặc trở lại vô

ứng dụng sẽ nhận được một NullPointerException trong một số trường hợp cạnh
hai là mâu thuẫn.

Nếu bạn đang thực sự chắc chắn rằng bạn alwasy có pieces[i].isBlank() sau đó ném IllegalStateException

Nếu không xử lý các trường hợp theo yêu cầu của bạn.

0

nếu mảng của bạn phải luôn có giá trị hợp lệ để trả lại, bạn nên tăng ngoại lệ làm dự phòng. (Trường hợp 2sd trong ví dụ của bạn)

Cuối cùng, bạn có thể khai báo loại ngoại lệ (Loại) của riêng bạn.

0

Tôi khuyên bạn nên sử dụng loại dữ liệu Maybe (còn được gọi là Option) mà tôi vừa mới nói đến trong số another answer cách đây không lâu.

Loại dữ liệu này is available trong Functional Java.

Cách sử dụng:

private Option<MyObject> findBlank() { 
    for (int i = 0; i < pieces.length; i++) { 
     if(pieces[i].isBlank()){ 
      return Option.some(pieces[i]); 
     } 
    } 
    return Option.none(); 
} 

Sidenote:

phương pháp findBack của bạn có thể được khái quát hóa đến một phương pháp mà phải mất một vị ngữ như một cuộc tranh cãi, và tìm thấy và trả về phần tử đầu tiên thỏa mãn điều đó.

Không có gì đáng ngạc nhiên, Functional Java already has that as well.

Giả sử trong giây lát piecesfj.data.List. Sau đó, phương pháp của bạn có thể được viết lại như sau:

private Option<MyObject> findBlank() { 
    return pieces.find(new F1<MyObject, Boolean>() { 
    public Boolean f(MyObject p) { 
     return p.isBlank(); 
    } 
    }); 
} 

Một sidenote:

Có lẽ mã trên có vẻ khá gnarly. IntelliJ IDEA's "closure folding" can be of some help here.

+0

Tìm thêm thịt [tại đây] (http://goo.gl/E7lQ7). – missingfaktor

0

Có thể nên sử dụng Null Object pattern.

Provide an object as a surrogate for the lack of an object of a given type. The Null Object provides intelligent do nothing behavior, hiding the details from its collaborators

Vì vậy, trong trường hợp đó bạn sẽ không phải sử dụng ngoại lệ hoặc trả lại null. Bạn luôn có thể trả về đối tượng kiểu trả về dự định.Bí quyết là khi bạn không có gì để trả lại, thay vì trả lại null hoặc ném một ngoại lệ, bạn có thể trả lại số Null object cùng loại với kiểu trả về dự định.

Điều này documentation có một số ví dụ và mô tả. Và có một trường hợp tương tự như bạn, được giải quyết bằng mẫu thiết kế.

public class CustomerFactory { 

    public static final String[] names = {"Rob", "Joe", "Julie"}; 

    public static AbstractCustomer getCustomer(String name){ 
    for (int i = 0; i < names.length; i++) { 
     if (names[i].equalsIgnoreCase(name)){ 
     return new RealCustomer(name); 
     } 
    } 
    return new NullCustomer(); 
    } 
} 
+0

https://www.cs.oberlin.edu/~jwalker/nullObjPattern/ – prime

0

Ngoài hầu hết các câu trả lời tôi muốn chỉ ra rằng nếu hiệu suất là mối quan tâm của bạn sau đó, Exceptions là cách chậm hơn so với trở về vô

Hãy nhìn vào mã này:

class Main { 
    public static void main(String[] args) { 
     testException(); 
     testNull(); 
    } 

    public static void testException() { 
     long st = System.currentTimeMillis(); 
     for(int i=0;i<10000000;i++) { 
      try{ 
       exp(); 
      } catch(Exception e) { 

      } 
     } 
     long et = System.currentTimeMillis(); 
     System.out.println("Time taken with exceptions : "+(et-st)); 
    } 

    public static void testNull() { 
     long st = System.currentTimeMillis(); 
     for(int i=0;i<10000000;i++) { 
      returnNull(); 
     } 
     long et = System.currentTimeMillis(); 
     System.out.println("Time taken with null : "+(et-st)); 
    } 

    public static void exp() throws Exception { 
     throw new Exception(); 
    } 

    public static Object returnNull() { 
     return null; 
    } 
} 

Các kết quả trên máy tính của tôi là:

Time taken with exceptions : 7526 
Time taken with exceptions : 5 

Nếu trường hợp ngoại lệ ném là điều kiện hiếm hoi trong mã của bạn và sẽ không xảy ra thường xuyên thì thời gian thực hiện trong cả hai tình huống gần như giống nhau.

Bạn sẽ phải thực hiện Hiệu suất và khả năng duy trì/Khả năng đọc trao đổi.

đọc thêm về nó here

0

Return rỗng hầu hết thời gian sẽ rút ra những thông tin bị mất khỏi tầm nhìn hợp đồng, người tiêu dùng có thể không biết lý do của sự phản ứng sai là gì nếu nhận được null từ nhà sản xuất.

Nhìn mã đầu tiên của bạn, có hai tình huống mã bên ngoài có được NullPointerException: 1. mảnh là null 2. mảnh không có yếu tố như

Vì vậy, trở về null ý mis-dẫn bên ngoài mã cho hoạt động tiếp theo, nó sẽ rút ra vấn đề tiềm ẩn.

Và nói về sự khác biệt giữa return nullObject (không null) và ngoại lệ, sự khác biệt chính là PROBABILITY, có nghĩa là: 1. Nếu tình trạng trống có nhiều xác suất hơn, nó sẽ trả về nullObject sao cho TẤT CẢ mã bên ngoài có thể/nên xử lý chúng một cách rõ ràng. 2. Nếu tình huống trống là ít xác suất, tại sao không ném ngoại lệ để chức năng cuộc gọi cuối cùng có thể xử lý trực tiếp.

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