为什么ImmutableSet允许重复值,但ImmutableMap不允许呢?

10

我注意到(并感谢!)Guava的ImmutableMap.Builder在向构建器中添加重复键时会失败。然而,使用ImmutableSet添加重复元素会成功。

这种差异有原因吗?是否有一种好的方法可以构建一个具有相同失败行为的ImmutableSet

测试用例:

import static org.testng.Assert.*;
import org.testng.annotations.Test;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

public class ImmutableDuplicatesTest
{
    @Test(expectedExceptions=IllegalArgumentException.class) // Note failure
    public void mapDuplicates() {
        ImmutableMap.Builder<String, String> map = ImmutableMap.builder();
        map.put("a", "a");
        map.put("b", "b");
        map.put("a", "c");
        assertEquals(map.build().size(), 2);
    }

    @Test // Passes normally
    public void setDuplicates() {
        ImmutableSet.Builder<String> set = ImmutableSet.builder();
        set.add("a");
        set.add("b");
        set.add("a");
        assertEquals(set.build().size(), 2);
    }
}

1
我猜集合(sets)的设计是让你可以输入相同的内容两次,并且只会保留一份副本。然而,使用映射表(map)时,如果将同一个键(key)映射到一个新值(value),它会覆盖旧值,这可能不是预期的行为。 - Cruncher
然而,无论值是否相同都没有关系,在任何重复键上它都会快速失败。 - dimo414
1个回答

10

是的,这种行为是有意的。这是一种思考方式:Set通常是从其他Collection(尤其是List)创建的,这些集合可能会有重复项。如果存在重复项,让用户编写ImmutableSet.copyOf(Sets.newHashSet(element))将非常笨拙和低效。另一方面,Map通常是从其他不能具有重复键的Map构建的。

如果您想禁止重复元素,最好的选择是:

Set<E> set = new LinkedHashSet<E>();
for (E e : input) {
  if (!set.add(e)) {
    throw new IllegalArgumentException();
  }
}
return ImmutableSet.copyOf(set);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接