2013-02-08 14 views
17

Tôi muốn biết tại sao HashSet, LinkedHashSet và TreeSet thực hiện không cho phép các phần tử null? Bất cứ khi nào tôi cố gắng biên dịch mã sau nó ném con trỏ null.Tại sao giao diện Thiết lập không cho phép các phần tử null?

public static void main(String[] args) { 

    HashSet<Integer> hashSet = new HashSet<Integer>(); 

    hashSet.add(2); 
    hashSet.add(5); 
    hashSet.add(1); 
// hashSet.add(null); will throw null pointer 
    hashSet.add(999); 
    hashSet.add(10); 
    hashSet.add(10); 
    hashSet.add(11); 
    hashSet.add(9); 
    hashSet.add(10); 
    hashSet.add(000); 
    hashSet.add(999); 
    hashSet.add(0); 

    Iterator<Integer> it = hashSet.iterator(); 
    while(it.hasNext()){ 
     int i = it.next(); 
     System.out.print(i+" "); 
    } 
    } 

Vui lòng hướng dẫn tôi.

+14

tiêu đề gây nhầm lẫn. Ví dụ. Tài liệu 'HashSet' nói rõ ràng * Lớp này cho phép phần tử null. * – Abdull

Trả lời

44

Đây là lý do tại sao tôi không thích dựa vào auto-boxing. Bộ sưu tập Java không thể lưu trữ nguyên thủy (vì bạn sẽ cần API của bên thứ ba như Trove). Vì vậy, thực sự, khi bạn thực thi mã như thế này:

hashSet.add(2); 
hashSet.add(5); 

gì đang thực sự xảy ra là:

hashSet.add(new Integer(2)); 
hashSet.add(new Integer(5)); 

Thêm một null vào tập băm là không vấn đề, rằng công trình phần bình thường. NPE của bạn đến sau, khi bạn cố gắng và Unbox giá trị của bạn thành một int nguyên thủy:

while(it.hasNext()){ 
    int i = it.next(); 
    System.out.print(i+" "); 
} 

Khi giá trị null đang gặp phải, JVM cố gắng Unbox nó thành một int nguyên thủy, dẫn đến một NPE. Bạn nên thay đổi mã của bạn để tránh tình trạng này:

while(it.hasNext()){ 
    final Integer i = it.next(); 
    System.out.print(i+" "); 
} 
+7

Trên thực tế '2' được tự động hóa bằng cách gọi' Integer.valueOf (2) ' –

+1

Tôi đang thêm null vào ArrayList và nó không phải là ném NPE.{ \t \t ArrayList list = new ArrayList (); \t \t \t \t System.out.println ("kích thước ban đầu của mảng là:" + list.size()); \t \t list.add (4); \t \t list.add (2); \t \t list.add (8); \t \t list.add (9); \t \t list.add (3); \t \t list.add (7); \t \t list.add (1); \t \t list.add (null); \t \t list.add (0,12); \t \t \t \t Iterator iterator = list.iterator(); \t \t trong khi (iterator.hasNext()) { \t \t \t System.out.println (iterator.next()); \t \t} – nakul

+4

@nakul - 'ArrayList' cho phép các phần tử rỗng, giống như' HashSet'. Vấn đề với mã của bạn không liên quan gì đến việc thêm vào 'HashSet', nó phải làm với việc lấy các phần tử từ' HashSet' vào một nguyên thủy. – Perception

4

Điểm của giao diện Set là sử dụng thông tin về các phần tử (mã băm hoặc so sánh) để thực hiện triển khai nhanh hơn.

null không có thông tin đó.

+3

Mặc dù hầu hết các triển khai sẽ không chấp nhận' null', 'null' hoàn toàn độc đáo với quan điểm' Set'. Các tài liệu nói rằng ["Một ​​số cài đặt có các hạn chế về các phần tử mà chúng có thể chứa"] (http://docs.oracle.com/javase/7/docs/api/java/util/Set.html); điều này không phổ biến cho tất cả các triển khai theo định nghĩa (mặc dù câu trả lời là hợp lệ cho mã OP được cung cấp). – akaIDIOT

19

1) Bạn có chắc chắn về việc bạn nhận được thời gian biên dịch lỗi? Tôi không nghĩ như vậy, tôi đoán mã ném NPE khi chạy ở

int i = it.next();

2) Như một vấn đề của thực tế giao diện java.util.Set không cấm yếu tố null, và một số JCF Set triển khai cho phép yếu tố vô quá:

Set API - A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.

HashSet API - This class permits the null element.

LinkedHashSet API - This class provides all of the optional Set operations, and permits null elements

TreeSet.add API - throws NullPointerException - if the specified element is null and this set uses natural ordering, or its comparator does not permit null elements

-1
public class JavaHashSetTest { 


    public static void main(String[] args) { 
     Set<Integer> hashset= new HashSet<Integer>(); 

     hashset.add(null); 
     hashset.add(22); 
     hashset.add(222); 
     hashset.add(null); 
     hashset.add(11); 
     hashset.add(233); 
     // TreeSet<String> tset=hashset; 

     Iterator<Integer> it = hashset.iterator(); 
     while(it.hasNext()){ 
      Integer i = it.next(); 
      System.out.print(i+" "); 
     } 
    } 

} 

Mã của tôi đang làm việc và tại sao nó sẽ cung cấp cho bạn Nullpointer tôi đã cố gắng sắp xếp HashSet có chứa giá trị Null sau đó nó sẽ cung cấp cho bạn ngoại lệ khác nó hoạt động khỏe.

+1

Mã của bạn hoạt động vì bạn đã sử dụng 'Số nguyên i = it.next();' Trong trường hợp bạn sử dụng 'int i = it.next();' sau đó bạn sẽ nhận được ngoại lệ. Iterator được cho là cung cấp cho đối tượng kiểu Integer từ phương thức next() của nó và khi chúng ta cố gắng lưu trữ nó trong kiểu nguyên thủy thì intValue() được định nghĩa trong Integer.java được gọi. Vì tham chiếu là null nên nó được gọi trên một null và nó dẫn đến NPE. –

1

Đặt cho phép thêm null để không phải là vấn đề. Thứ hai chương trình Java cần phải được biên dịch đầu tiên để chuyển đổi nó trong mã byte và sau đó nó được thực thi. NullPointerException là một ngoại lệ được ném trong thời gian chạy. Thời gian biên dịch nó không phải là một vấn đề. Bây giờ, hãy phân tích tại sao bạn nhận được NPE.

Iterator ở đây có nghĩa vụ phải xuất đối tượng loại Integer và chúng tôi muốn lưu trữ kết quả theo biến số primitive type int. Integer là một lớp có thể có tham chiếu kiểu của nó để tham chiếu đến null nhưng các kiểu nguyên thủy không thể giữ các giá trị null.

Iterator<Integer> it = hashSet.iterator(); // Iterator of Type Integer 
while(it.hasNext()){ 
    int i = it.next(); // it.next outputs Integer, but result is tried to be held in a primitive type variable 
    System.out.print(i+" "); 
} 

Khi int i = it.next(); được thực hiện sau đó public int intValue() được gọi để chuyển đổi các đối tượng của Integer để int nguyên thủy. Khi it.next() trả về null thì null.intValue() được thực hiện với kết quả là NullPointerException.

nếu Integer được sử dụng thay vì int sau đó sẽ không có ngoại lệ

Integer i = it.next(); 
-1

Thêm null để các bộ sưu tập như HashSet ArrayList sẽ tạo ra vấn đề chỉ khi bộ sưu tập được sử dụng để sắp xếp. Khác hơn là null sẽ làm việc cho iterator và kịch bản bình thường để hiển thị nội dung của danh sách hoặc thiết lập.

-1

Đặt giao diện nội bộ sử dụng lớp triển khai HashMap. Khi chúng ta sử dụng add() giá trị được cung cấp của chúng ta được lưu trữ trong Map làm khóa cho giá trị nó tạo ra một đối tượng rỗng.

Vì vậy, bản đồ không cho phép trùng lặp.

+0

"Đặt giao diện nội bộ sử dụng HashMap". Không. Một số triển khai chuẩn của Set có thể sử dụng HashMap. Nhưng giao diện không buộc bạn phải làm như vậy. – JacksOnF1re

3

Đặt giao diện không cho phép null vì trong TreeSet, Nó lưu trữ phần tử theo thứ tự sắp xếp để mỗi lần chúng tôi thêm phần tử mới thì nó so sánh giá trị và sau đó sắp xếp. vì vậy nội bộ những gì xảy ra là nó so sánh giá trị null mới được thêm vào với các giá trị hiện có để nó sẽ ném NullPointerException.

String str=null; 
if(str.equals("abc")) 
{ 
} 
//it will throw null pointer exception 

Đó là lý do tại sao nó không cho phép giá trị null.

4

Không, Đặt giao diện cho phép giá trị rỗng chỉ thực hiện của nó tức là TreeSet không cho phép giá trị null.

ngay cả khi bạn không viết mã lặp lại và chỉ có oTreeSet.add(null) trong mã của bạn nó biên dịch và tại thời gian chạy là nó ném NullPointerException.

TreeSet phương pháp add() lớp của nội bộ gọi put() phương pháp giá trị TreeMap null không được phép như sau mã trong đặt phương pháp()

if (key == null) 
    throw new NullPointerException();