2010-10-22 34 views
30

Tôi có một bản đồ của các hằng số, như thế này:Khi nào thì unmodifiablemap (thực sự) cần thiết?

private static Map<String, Character> _typesMap = 
     new HashMap<String, Character>() { 
     { 
      put ("string", 'S'); 
      put ("normalizedString", 'N'); 
      put ("token", 'T'); 
      // (...) 
     } 

Tôi có thực sự cần phải sử dụng Collections.unmodifiableMap() để tạo bản đồ này? Lợi thế của việc sử dụng nó là gì? Có bất kỳ nhược điểm của việc không sử dụng nó, bên cạnh thực tế rõ ràng rằng họ không thực sự trở thành liên tục?

+3

Bạn không thích 'final'? –

+20

cuối cùng sẽ không làm cho bản đồ không thay đổi được, chỉ là tham chiếu đến bản đồ. Bạn vẫn có thể gọi các phương thức (như 'put') trên các tham chiếu cuối cùng. –

+0

Trong ví dụ này, 'final' là cần thiết. (Trừ khi '_typesMap' được đặt lại thành một bản đồ khác sau này ...) –

Trả lời

59

Collections.unmodifiableMap đảm bảo rằng bản đồ sẽ không bị sửa đổi. Đó chủ yếu là hữu ích nếu bạn muốn quay trở lại một cái nhìn chỉ đọc của một bản đồ nội bộ từ một cuộc gọi phương pháp, ví dụ:

class A { 
    private Map importantData; 

    public Map getImportantData() { 
     return Collections.unmodifiableMap(importantData); 
    } 
} 

này cung cấp cho bạn một phương pháp nhanh chóng mà không có nguy cơ khách hàng thay đổi dữ liệu của bạn. Bộ nhớ nhanh hơn và hiệu quả hơn nhiều so với trả lại bản sao của bản đồ. Nếu khách hàng thực sự muốn sửa đổi giá trị trả lại thì họ có thể tự sao chép nó, nhưng những thay đổi đối với bản sao sẽ không được phản ánh trong dữ liệu của A.

Nếu bạn không trả lại các tham chiếu bản đồ cho bất kỳ ai khác thì đừng bận tâm làm cho nó không thể sửa đổi được trừ khi bạn hoang tưởng về việc biến nó thành bất biến. Bạn có thể tin tưởng chính mình để không thay đổi nó.

+3

"Bộ nhớ nhanh hơn và hiệu quả hơn nhiều so với trả lại bản sao của bản đồ". - đó là điều tôi muốn biết. :-) –

-2

Gói bản đồ là để đảm bảo người gọi sẽ không thay đổi bộ sưu tập. Mặc dù điều này hữu ích khi thử nghiệm, bạn thực sự nên tìm loại lỗi này ở đó, nó có thể không hữu ích trong sản xuất. Cách giải quyết đơn giản là có trình bao bọc của riêng bạn như thế nào.

public static <K,V> Map<K,V> unmodifiableMap(Map<K,V> map) { 
    assert (map = Collections.unmodifiableMap(map)) != null; 
    return map; 
} 

Chỉ bao gồm bản đồ khi xác nhận được bật.

+0

"nó có thể không hữu ích trong sản xuất" - tại sao? Đó là quan điểm của tôi, nó có hữu ích không? là nó thực sự cần thiết? –

+0

Nếu bạn kiểm tra nó đúng cách trong môi trường thử nghiệm, điều này không cần thiết trong sản xuất bởi vì bạn đã kiểm tra rằng bộ sưu tập không bao giờ được sửa đổi. –

+1

Trừ khi bạn đã kiểm tra mọi đường dẫn mã trong môi trường thử nghiệm của mình, bạn không thể chắc chắn. Nếu bạn bỏ lỡ một đường dẫn mã, nó thường tốt hơn để không nhanh (ngay cả trong sản xuất) hơn để cho bộ sưu tập được sửa đổi và gây ra một số khó khăn để gỡ rối vấn đề xa hơn xuống dòng. – Kelvin

24
tuyên bố

Cameron Skinner trên rằng "đảm bảo Collections.unmodifiableMap rằng bản đồ sẽ không được sửa đổi" thực sự là chỉ phần đúng nói chung, mặc dù nó sẽ xảy ra là chính xác cho các ví dụ cụ thể trong câu hỏi (chỉ vì nhân vật đối tượng là không thay đổi). Tôi sẽ giải thích với một ví dụ.

Bộ sưu tập.unmodifiableBản đồ thực sự chỉ cung cấp cho bạn bảo vệ rằng tài liệu tham khảo đối với các đối tượng được giữ trong bản đồ không thể thay đổi. Nó làm điều đó bằng cách hạn chế 'đưa' vào bản đồ mà nó trả về. Tuy nhiên, bản đồ đóng gói ban đầu vẫn có thể được sửa đổi từ bên ngoài lớp vì Collections.unmodifiableMap không tạo ra bất kỳ bản sao nào của nội dung của bản đồ.

Trong câu hỏi được đăng bởi Paulo, các đối tượng Ký tự được giữ trong bản đồ may mắn không thể sửa đổi được. Tuy nhiên, nói chung điều này có thể không đúng và tính không thể sửa đổi được quảng cáo bởi Collections.unmodifiableMap không nên là biện pháp bảo vệ duy nhất. Ví dụ, xem ví dụ bên dưới.

import java.awt.Point; 
import java.util.Collections; 
import java.util.HashMap; 
import java.util.Map; 

public class SeeminglyUnmodifiable { 
    private Map<String, Point> startingLocations = new HashMap<>(3); 

    public SeeminglyUnmodifiable(){ 
     startingLocations.put("LeftRook", new Point(1, 1)); 
     startingLocations.put("LeftKnight", new Point(1, 2)); 
     startingLocations.put("LeftCamel", new Point(1, 3)); 
     //..more locations.. 
    } 

    public Map<String, Point> getStartingLocations(){ 
     return Collections.unmodifiableMap(startingLocations); 
    } 

    public static void main(String [] args){ 
    SeeminglyUnmodifiable pieceLocations = new SeeminglyUnmodifiable(); 
    Map<String, Point> locations = pieceLocations.getStartingLocations(); 

    Point camelLoc = locations.get("LeftCamel"); 
    System.out.println("The LeftCamel's start is at [ " + camelLoc.getX() + ", " + camelLoc.getY() + " ]"); 

    //Try 1. update elicits Exception 
    try{ 
     locations.put("LeftCamel", new Point(0,0)); 
    } catch (java.lang.UnsupportedOperationException e){ 
     System.out.println("Try 1 - Could not update the map!"); 
    } 

    //Try 2. Now let's try changing the contents of the object from the unmodifiable map! 
    camelLoc.setLocation(0,0); 

    //Now see whether we were able to update the actual map 
    Point newCamelLoc = pieceLocations.getStartingLocations().get("LeftCamel"); 
    System.out.println("Try 2 - Map updated! The LeftCamel's start is now at [ " + newCamelLoc.getX() + ", " + newCamelLoc.getY() + " ]");  } 
} 

Khi bạn chạy ví dụ này, bạn sẽ thấy:

The LeftCamel's start is at [ 1.0, 3.0 ] 
Try 1 - Could not update the map! 
Try 2 - Map updated! The LeftCamel's start is now at [ 0.0, 0.0 ] 

Các startingLocations bản đồ được đóng gói và chỉ trở lại bằng cách tận dụng Collections.unmodifiableMap trong phương pháp getStartingLocations. Tuy nhiên, lược đồ bị hủy bằng cách truy cập vào bất kỳ đối tượng nào và sau đó thay đổi nó, như được thấy trong phần "Thử 2" trong đoạn mã trên. Đủ để nói rằng người ta chỉ có thể dựa vào Collections.unmodifiableMap để cung cấp cho một bản đồ thực sự unmodifiable NẾU các đối tượng tổ chức trong bản đồ là mình không thay đổi. Nếu không, chúng tôi muốn sao chép các đối tượng trong bản đồ hoặc hạn chế quyền truy cập vào các phương thức sửa đổi của đối tượng, nếu có thể.

+0

cảm ơn bạn đã làm rõ – charany1

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