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

Java 为什么要使集合不可修改?,java,collections,Java,Collections,我知道如何使集合在java中不可修改,但我不理解这种方法存在的必要性。有人能用一个我想使我的收藏不可修改的示例场景来解释这一点吗 提前感谢在类外共享私有数据最有效的方法就是简单地返回它。但是类之外的东西可以改变类所依赖的数据。另一种选择是在共享之前复制数据。这需要时间和内存来完成。不可修改的集合通常会包装数据,并在不允许外部类编辑的情况下简单地呈现数据。这比复制要快。如果需要,外部类可以选择创建可修改的副本。在类外共享私有数据的最有效方法是简单地返回它。但是类之外的东西可以改变类所依赖的数据。另

我知道如何使集合在java中不可修改,但我不理解这种方法存在的必要性。有人能用一个我想使我的收藏不可修改的示例场景来解释这一点吗


提前感谢

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

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

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

它还促进了不变性,这通常是一件好事,因为在程序的其余执行过程中,您不必关心集合的状态。参见有效Java(第二版)第15项:最小化可变性,并引用Joshua Bloch的话:

不可变对象很简单。一个不可变的对象可以精确地处于 一个状态,创建它的状态


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

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

它还促进了不变性,这通常是一件好事,因为在程序的其余执行过程中,您不必关心集合的状态。参见有效Java(第二版)第15项:最小化可变性,并引用Joshua Bloch的话:

不可变对象很简单。一个不可变的对象可以精确地处于 一个状态,创建它的状态


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

在许多情况下,您不希望集合可修改。只要您知道集合在任何时候都是用它应该包含的内容初始化的,它就可以提供安全性,使其不可修改


另一个用户提供的(相当长的)示例是一个很好的例子,说明了它经常导致问题的地方。每当遍历集合时,如果忘记对副本执行更改,则存在更改集合的风险。使集合不可修改会捕获并防止这一容易出错的情况。

在许多情况下,您不希望集合可修改。只要您知道集合在任何时候都是用它应该包含的内容初始化的,它就可以提供安全性,使其不可修改


另一个用户提供的(相当长的)示例是一个很好的例子,说明了它经常导致问题的地方。每当遍历集合时,如果忘记对副本执行更改,则存在更改集合的风险。使集合不可修改会捕获并防止这一容易出错的情况。

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

因此,我们必须使用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 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());
    }
}
在UsersHolder中返回unmodifiableMap时,将无法删除。唯一的方法是创建一个新的地图,让用户通知,这样我们的用户就安全了

这个例子有点大,很抱歉,我没有想到/创建一些更短的


不可修改映射有助于使类保持不变,这是安全的(如示例中所示),特别是在多线程环境中。

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

因此,我们必须使用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 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());
    }
}
在UsersHolder中返回unmodifiableMap时,将无法删除。唯一的方法是创建一个新的地图,让用户通知,这样我们的用户就安全了

这个例子有点大,很抱歉,我没有想到/创建一些更短的


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

但有一点很重要,即通常,无论是否不可修改,共享类的内部工作都不是最佳做法。如果遇到这种情况,通常最好进行封装(即方法首先驻留在集合所属的类中)。请注意,虽然您可能引用的方法(即
集合
Created user Peter
Created user Paul
Number of users before notification: 2
notifyingUsers: Paul
Number of users after notification: 1