【问题标题】:Java Set - Which is faster Set.add() or Set.addAll()?Java Set - Set.add() 或 Set.addAll() 哪个更快?
【发布时间】:2015-09-26 16:41:06
【问题描述】:

Set 维护唯一记录并在尝试复制现有元素时更新现有记录。

考虑以下两种情况。您认为两者之间的哪个代码会更快更高效?

场景 1:使用 addAll()

Set<String> uniqueSet = new HashSet<String>();
uniqueSet = getSomedata(param1);
uniqueSet.addAll( getSomedata(param2) );

这里getSomedata() 只是返回数据集合,该方法中没有特殊逻辑。

场景 2:使用 add()

Set<String> uniqueSet = new HashSet<String>();
getSomedata(param1, uniqueSet);
getSomedata(param2, uniqueSet );

这里getSomedata()如下

void getSomedata(String param, Set<String> uniqueSet){
    while (someCollection.hasNext()){
        uniqueSet.add( someCollection.get() );
    }
}

【问题讨论】:

  • 看一下实现,在JDK自带的src.zip里。如果您正确设置了 IDE,您应该可以在那里查看它。
  • 首先,第一个sn-p不应该创建一个无用的空HashSet。其次,你应该争取的不是表现。这两者之间的差异可能微不足道。你应该争取的是可读性和可维护性。我希望一个名为 getSomedata() 的方法返回一些数据。不要将 Set 作为参数,填充它,并且什么也不返回。如果您想将数据添加到 List 而不是 Set 怎么办?或者如果你只是想迭代它?第一个更自然,更易于理解和使用。
  • @JBNizet,实际上在我的应用程序中,我正在从服务器公开的文件中读取大量数据。文件中的行是唯一的,但可以在多个文件中重复。从所有文件中收集数据后,我只需要处理唯一的记录。如您所知,List 不强制唯一性。因此我选择了 Set。
  • 花在 IO 上的时间可能比花在处理集合上的时间大得多。使用您认为最易读的内容,并仅在需要时进行优化。

标签: java collections set


【解决方案1】:

addAll 基本上迭代它给定的集合并在每个方法上调用add。以下是 OpenJDK8 的实现方式:

public boolean addAll(Collection<? extends E> c) {
    boolean modified = false;
    for (E e : c)
        if (add(e))
            modified = true;
    return modified;
}

但作为一般经验法则,除非您绝对确定可以发明更好的轮子,否则您不应该尝试发明轮子。

【讨论】:

  • 仅供参考,JDK 7也一样。
  • 据我了解,问题不在于 addAll() 与 add(),而是每个方法调用创建自己的小集合,然后将它们全部添加到唯一的大集合中,与创建唯一集并让方法将数据添加到此唯一集。
【解决方案2】:

您的问题不完整。让我们用实际的替代方案来完成它。

首先,您有一个填充提供的Set 的方法:

void getSomedata(String param, Set<String> uniqueSet)

必须像这样使用

Set<String> uniqueSet = new HashSet<String>();
getSomedata(param1, uniqueSet);
getSomedata(param2, uniqueSet);

另一种方法是有一个方法返回一个新的Set

Set<String> getSomedata(String param)

你可以像这样使用

Set<String> uniqueSet = getSomedata(param1);
uniqueSet.addAll( getSomedata(param2) );

在这种情况下,您将忽略 getSomedata 方法将如何创建和填充它将返回的 Set。显然,除非它创建一个自定义的Set 实现来投影源数据,否则它必须创建一个Set 并在返回之前用元素填充它。

换句话说,addAll 是如何实现的并不重要,在您要调用它时,该解决方案已经执行了与其他替代方案相同的工作,因为它已经添加了所有元素到Set。因此,即使特定 Set 实现的 addAll 有优化,它的工作也会增加已经执行的工作,即单独将所有元素添加到 Set


不过,除非存在真正的性能问题,否则您不应该担心性能的规则仍然适用。涉及的 I/O 可能比这一切都重要。或者热点优化和内存管理效果的不可预测性可能会改变这一切。如果您认为 getSomedate 返回一个新的 Set 更干净(这是合理的),请使用它。


作为附录,我简化了一点。 HashSet 只是理论上的O(1),但是在存在哈希冲突时会执行不同的操作,并且在使用TreeSets 的情况下,具有O(log n) 时间复杂度,不同大小的集合会产生影响,因此,在不同大小的集合上运行的替代方案并不完全具有可比性,这取决于使用了哪些Set 实现以及其他周围环境。但趋势仍然相同,尤其是在大多数情况下,没有优化的addAll 实现(EnumSet 可能是唯一的例外)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    • 2012-10-03
    • 2011-02-15
    • 2012-07-21
    相关资源
    最近更新 更多