2017-07-24 20 views
5

Tôi đang cố xóa tất cả mục nhập có giá trị là null. Mã này là:Tại sao trình vòng lặp trên map.vaules có thể được sử dụng để xóa HashMap # Entry?

Map<String, String> map = new HashMap<>(); 
map.put("one", null); 
map.put("two", null); 
map.put("three", "THREE"); 

Iterator iterator = map.values().iterator(); 
while (iterator.hasNext()) 
{ 
    if (iterator.next() == null) { 
     iterator.remove(); 
    } 
} 

for (Map.Entry<String, String> e : map.entrySet()) { 
    System.out.println(e.getKey() + ":" + e.getValue()); 
} 

Câu hỏi của tôi là iterator được liên kết với map.values, tại sao nó có thể loại bỏ toàn bộ tuyển sinh?

+0

Chỉ cần xác nhận, mã của bạn hoạt động nhưng bạn đang cố gắng hiểu tại sao. Chính xác? – shmosel

+0

Có. Tôi đang cố tìm nguyên nhân gốc rễ. – caisil

Trả lời

8

Có thể vì Map#values trả lại chế độ xem các giá trị là được hỗ trợ bởi bản đồ.

Từ chính thức Java-Doc of Map#values:

Trả về một quan điểm Bộ sưu tập của các giá trị chứa trong bản đồ này. Bộ sưu tập được bản đồ sao lưu, vì vậy các thay đổi đối với bản đồ được phản ánh trong bộ sưu tập và ngược lại. [...] Bộ sưu tập hỗ trợ xóa phần tử, loại bỏ ánh xạ tương ứng khỏi bản đồ, qua Iterator.remove, Collection.remove, removeAll, retainAll và xóa các thao tác. Nó không hỗ trợ các hoạt động thêm hoặc addAll.


Lưu ý rằng lớp AbstractMap, từ đó hầu hết các trường bản đồ mở rộng, có thêm một trường transient volatile Collection<V> values và đó là chính xác những gì bạn sẽ đạt được điều đó. Khi bạn thấy bộ sưu tập được Bản đồ sử dụng nội bộ và do đó các thay đổi trên bản đồ cũng được phản ánh trên Bản đồ. Xem thêm: Source code of AbstractMap


Nếu bạn muốn đi vào chi tiết, hãy xem tại AbstractMap#values phương pháp trong mã nguồn. Ở đó, họ tạo các giá trị là một trình bao bọc hoạt động trên bản đồ gốc. Ví dụ: phương thức next lặp lại trên các mục Entry<K, V> của Bản đồ nhưng chỉ trả về giá trị của chúng với Entry#getValue và cứ tiếp tục như vậy.
Ngoài ra, phương pháp remove, như bạn có thể thấy, được chuyển qua trình lặp của Entry<K, V>, do đó việc xóa sẽ cuối cùng được thực thi trên bản đồ gốc một lần nữa.

2

giải thích đã được đưa ra bởi Zabuza, nhưng bởi vì có cách thích hợp để loại bỏ các yếu tố của bạn, tôi viết chúng:


Để loại bỏ Entry với giá trị null bạn có thể sử dụng Streams:

map = map.entrySet() 
     .stream() 
     .filter(entry -> entry.getValue()!=null) 
     .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue)); 

Hoặc trong một dòng: map.entrySet().removeIf(e -> e.getValue()==null);

Hoặc : map.values().removeIf(v -> v == null)

+1

Hoặc 'map.values ​​(). RemoveIf (v -> v == null)'. Nhưng tôi nghĩ bạn đã bỏ lỡ điểm của câu hỏi. – shmosel

+0

@shmosel yes Tôi chỉ nhận ra^^ – azro

+0

@azro @shmosel, từ mã 'Collection.removeIf', tôi nghĩ về phương pháp' removeIf' giống như phương thức được sử dụng trong mã mẫu của tôi, cả hai đều dựa trên 'iterator' . – caisil

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