Guava Immutable*类是否满足它们实现的标准集合接口?

eva*_*ner 2 java collections interface immutability guava

例如,如果我有一个类似的界面

public interface Partition<E> {
    Set<E> getIncluded();
    Set<E> getExcluded();
}
Run Code Online (Sandbox Code Playgroud)

我这样实现它

public class ImmutablePartition<E> implements Partition<E> {
    private final ImmutableSet<E> included;
    private final ImmutableSet<E> excluded;

    ImmutablePartition(Set<E> included, Set<E> excluded) {
        this.included = ImmutableSet.copyOf(included);
        this.excluded = ImmutableSet.copyOf(excluded);
    }

    @Override 
    public Set<E> getIncluded() {
        return included;
    }

    @Override
    public Set<E> getExcluded() {
        return excluded;
    }
}
Run Code Online (Sandbox Code Playgroud)

我真的实现了原始界面的精神吗?如果客户端代码Set<E>返回,尝试操纵它,并获得一个UnsupportedOperationException,肯定会首先失败实现Set<E>接口的目的?

此问题适用于实现标准集合接口的所有Guava Immutable*集合java.util.

编辑:正如我在下面提醒的那样,Collection界面指定了UnsupportedOperationException不支持的变异方法.除非另有说明,我觉得期望仍然是返回的集合将允许修改.如果我想返回一个不可变集合,我会将返回类型指定为不可变类,如果可能的话.

我想我的问题是:通常的假设(根据我的经验)是返回的集合是可变的,实现一个返回一般集合并返回一个不可变集合的接口方法是否合理?

Hoo*_*pje 9

我不知道接口的精神是什么,但Java集合接口的规范(又名Javadoc ;-)清楚地表明,UnsupportedOperationException当用户尝试修改它们时,不可变集合可能会抛出.

编辑以回答您编辑的问题

首先,我同意应该记录返回的集合是否可变.但是,我不同意默认的假设是该集合是可变的.此外,当返回的集合是可变的时,我希望这是记录的,并且还记录了当我修改集合时会发生什么(特别是:当我修改集合时,集合来自哪个对象,或者它只是一些数据的副本).

拥有像ImmutableSet,ImmutableList等等类型可能会很好,但Java标准库没有它们.原因是情况不是布尔值:集合可以是部分可修改的,例如因为它允许删除元素但不允许添加新元素.为所有可能的组合设置单独的接口并不是一个好主意,因此Java设计者决定不使用任何接口.

您可以使用外部库,例如Guava,但这也有缺点:

  • 您将依赖项引入外部库
  • Guava不可变集合包含原始数据的副本,而不是视图.如果你的班级想要公开一些内部列表而没有调用者更改内部数据的可能性,那么每次复制都可能不是你想要的.

  • @evanjdooner.仅仅因为Java类型系统不知道集合是否可变,并不意味着*你*不知道它.通常你知道一个方法是否返回一个可变集合,例如因为该方法的Javadoc提到它.它与其他类型的约束相同.例如.如果你将`int`除以'0`,将抛出异常.这并不意味着您将在每个整数除法之前检查0,因为通常您知道变量不能为0. (4认同)

rko*_*egi 5

Do the Guava Immutable* classes satisfy the standard collection interfaces they implement?

YES.

接口方法调用的行为是特定于实现的,直到文档明确限制.投掷UnsupportedOperationException不违反接口合同.

示例:

java.util.Collections.UnmodifiableList,实现java.util.List如下:

public void remove() {
    throw new UnsupportedOperationException();
}
public void set(E e) {
    throw new UnsupportedOperationException();
}
public void add(E e) {
    throw new UnsupportedOperationException();
}
Run Code Online (Sandbox Code Playgroud)

如果检查List接口的特定方法的javadoc,例如,boolean add(E e)您可以找到以下内容:

  throws UnsupportedOperationException if the add operation
          is not supported by this list
Run Code Online (Sandbox Code Playgroud)