java - 如何实现一个可迭代的类并公开一个真正不可变的 API?

标签 java immutability

我想在Java中实现一个可迭代的不可变类。我按照以下方式进行:

public final class MyIterable implements Iterable<Integer> {

    private final Collection<Integer> items;

    public MyIterable(Collection<Integer> items) {
        this.items = Collections.unmodifiableCollection(new LinkedList<Integer>(items));
    }

    @Override
    public Iterator<Integer> iterator() {
        return items.iterator();
    }
}

这一切都很好,我无法改变我的实例中的任何内容。然而,我的类仍然公开了一个 API,表明可以通过迭代器上的 remove() 方法修改其内部结构:

MyIterable myIterable = new MyIterable(Arrays.asList(1, 2, 3));
for (Iterator<Integer> it = myIterable.iterator(); it.hasNext();) {
    it.remove(); // I do not want to expose this even 
                 // though I know it will throw an error at runtime.
    it.next();
}

是否有某种方法可以避免公开此删除方法,从而让我的类公开真正不可变的 API?理想的情况是实现类似 ReadOnlyIterable 的东西,但类似的东西在 Java 中似乎不可用。

最佳答案

它似乎通过其方法签名来表明这一点,但这些方法被专门记录为“不,我们不提供这些行为!”

为了实现这一点,您还必须记录您遵循与 UnmodifyingList 相同的行为。

开发人员有责任了解他们使用的库的用途库创建者有责任制作该信息可用

底线是,Iterable 已融入到语言中(for(a:b) 循环),而您可以创建自己的接口(interface) ReadOnlyIterable 它根本不会那么健壮。

这种方法的问题是牺牲了编译时完整性。换句话说,有人可以编译使用 remove() 方法的代码,直到运行时他们才会发现它不起作用。这意味着,如果它们碰巧没有正确测试,您将不会发现该方法不应该使用,直到投入生产。

您也许可以使用注释和警告来缓解这种情况 - 如果他们听取警告,或者使用告诉他们警告的 IDE,他们会更早发现。但是您不能依赖用户做正确的事情。这就是为什么你必须抛出异常而不是什么也不做。

关于java - 如何实现一个可迭代的类并公开一个真正不可变的 API?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13843777/

相关文章:

java - 无法覆盖 Kotlin 中的 Java 函数

java - 使用Bean组件处理Camel消息

java.lang.ClassNotFoundException : org. Spark_project.guava.collect.MapMaker

javascript - javascript 中的不可变类型

java - 如何知道一个页面是否在tomcat中被保护

java - 重定向到 JSP 而不是来自 REST 调用的 JSON 响应

c++ - RAII能否在没有同步的情况下有效地在线程之间共享不可变对象(immutable对象)

java - 数组的不可变数据结构替换

.NET ORM、不可变值对象、结构、默认构造函数和只读属性

ruby - 用相同的元素 : `==` operator says arrays are the same, 初始化一个数组,但它们的行为不同。为什么?