为什么要使集合不可修改?

时间:2014-08-18 12:09:25

标签: java collections

我知道如何在java中使集合不可修改,但我不明白是否需要存在这样的方法。有人可以用一个示例场景来解释这一点,我想让我的收藏品不可修改吗?

提前致谢

4 个答案:

答案 0 :(得分:8)

在类之外共享私有数据的最有效方法是简单地返回它。但是,类之外的东西可以改变类所依赖的数据。另一种选择是在共享之前复制数据。这需要时间和记忆。不可修改的集合通常会包装数据并简单地呈现它,而不允许外部类编辑它。这比制作副本要快。如果需要,外部类可以选择制作可修改的副本。

答案 1 :(得分:4)

不可修改的集合基本上是只读的,如果您需要此类集合发布到客户端代码并且您不希望客户端代码修改集合,这正是您想要的

它还提升了不变性,这通常是一件好事,因为你不必关心程序执行其余部分的集合状态。请参阅Effective Java(第2版)第15项:最小化可变性,引用Joshua Bloch:

  

不可变对象很简单。不可变对象可以完全正确   一个州,即创建它的州。

请注意,不可修改的集合使包含的对象不可变。如果当然需要,这是每个包含的对象需要确保的属性。

答案 2 :(得分:2)

看看这个场景。有一个应用程序可以创建2个用户,然后想要通知他们某些事情。但只有名字与彼得不同的用户才能收到通知。

所以我们必须使用User.class:

public class User {
    private String name;
    private Integer id;

    public User(final Integer id, final String name) {
        this.id = id;
        this.name = name;
    }
    public String getName() {
        return name;
    }

    public Integer getId() {
        return id;
    }
}

用户存储在特殊持有者类(包含地图)中:

public class UsersHolder {
    private static Map<Integer, User> usersMap = new HashMap<Integer, User>();

    public static void addUser(final User user) {
        usersMap.put(user.getId(), user);
    }

    public static Map<Integer, User> getUsersMap() {
        return usersMap;
        //return Collections.unmodifiableMap(usersMap);
    }
}

然后我们有UsersCreator创建这些用户并将它们存储在地图中:

public class UsersCreator {
    public static void createUsers() {
        UsersHolder.addUser(new User(1, "Peter"));
        System.out.println("Created user " + UsersHolder.getUsersMap().get(1).getName());
        UsersHolder.addUser(new User(2, "Paul"));
        System.out.println("Created user " + UsersHolder.getUsersMap().get(2).getName());
    }

    public static void main(String[] args) {
        UsersCreator.createUsers();
        System.out.println("Number of users before notification: " + UsersHolder.getUsersMap().size());
        new UsersNotificator().notifyAllUsersButPeters(UsersHolder.getUsersMap());
        System.out.println("Number of users after notification: " + UsersHolder.getUsersMap().size());
    }
}

除了彼得斯之外通知所有人的通知:

public class UsersNotificator {
    public void notifyAllUsersButPeters(final Map<Integer, User> map) {
        //we don't need peters, so we'll remove them from the list;
        Iterator<Entry<Integer, User>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            if (iterator.next().getValue().getName().equals("Peter")) {
                iterator.remove();
            }
        }
        //now we can notify all from the list;
        notifyUsers(UsersHolder.getUsersMap());
    }

    private void notifyUsers(Map<Integer, User> map) {
        for (final User user : map.values())
        System.out.println("notifyingUsers: " + user.getName());
    }
}

现在 - 通知人员被提供了一张地图,它可能会修改它。它不知道它不应该像它的全局用户地图一样修改它。实际上它删除了名为Peter的所有用户。它是为了它自己的目的而做的,但是使用UsersHolder的每个其他类都可以看到结果。

结果如下:

Created user Peter
Created user Paul
Number of users before notification: 2
notifyingUsers: Paul
Number of users after notification: 1

在UsersHolder中返回unmodifiableMap时,将无法删除。唯一的方法是创建用户通知的新地图,这样我们的usersHolder就是安全的。

这个例子有点大,对不起,我没想到/创造更短的时间。

不可修改的地图有助于保持您的类不可变,这是安全的(如示例中所示),尤其是在多线程环境中。

答案 3 :(得分:0)

在许多情况下,您不希望您的收藏品可以修改。每当你知道集合的初始化时,它应该始终包含它应该包含的内容,它可以提供安全性,使其无法修改。

另一个用户提供的(相当长的)示例是它经常导致问题的一个很好的例子。每当您遍历集合时,如果您忘记在副本上执行此操作,则存在更改集合的风险。使收集无法修改,并防止这容易犯错误。