加速HashSet和HashMap的性能

3
在Java中,我有以下代码:
Set<Integer> set = new HashSet<Integer>();
callVoidMethod(set);
...
public static void callVoidMethod(Set<Integer> set) {

    Set<Integer> superset = new HashSet<Integer>(set);
    ...
    // I just added this loop to show that I'm adding quite a lot
    // well, it depends on conditions, sometimes I add nothing,
    // but it is unpredictable and do not know if add something
    for (int i = 0; i < 1000; i++) {
         ...
         if (conditionSatisfied) superset.add(someValue);
         ...
    }

}

上面的代码简化了,其思想是通过引用将set传递到void方法中,并创建一个完整的set副本,以便我们能够向副本中添加一些新元素(这里是超集),并在退出void方法时不改变原始set,因为我们需要它不变。
我的代码处理大量数据,如果没有更快的复制方式,则我想优化HashSet本身,例如我不需要将Integer用作键,而是更好的原始int。是否在MyHashSet中实现int[]数组键是一个好主意?
如果可能的话,我有兴趣使用相同的想法来改进这个:
Map<Integer, ArrayList<Item>> map = new HashMap<Integer, ArrayList<Item>>();

编辑: 我只需要速度-性能-优化。我不需要美观可维护的代码和内存。


conditionSatisfied 一般是真还是假? - assylias
它实际上在一个for循环中,有时为真,有时为假。 - Sophie Sperner
这个集合可以有多少(超)级别? - Boris Treukhov
所以问题在于制作这个副本。我试图通过将元素保存在ArrayList中并在退出循环时从集合中删除它们来避免这种情况。然而,执行时间是相同的。我的第二个问题是关于一些足够实现HashSet的方法,我认为通过管理int键它会更快。 - Sophie Sperner
1
给Boris:一个集合只有一个超级集(超级层次结构)。但我经常调用这种方法。 - Sophie Sperner
这些集合在创建后可以是不可变的吗? - Boris Treukhov
3个回答

8

一般来说,如果你正在寻找允许使用基本类型的高速集合,请考虑使用Trove。我会说 - 除非你发现这实际上是一个瓶颈,否则不要进行优化。您或其他人需要维护此代码,并且阅读优化版本通常更难。


在这种特定情况下,TIntHashSet可能是执行此任务的适当工具。如果您需要它成为一个Set<Integer>,请将其包装在TIntSetDecorator中。(但话说回来,在这里我绝不会自己编写实现程序。) - Louis Wasserman

6

你尝试过先调整HashSet的初始容量和负载因子吗?

HashSet

这里有一篇帖子可能会对你有所帮助。

HashMap初始化参数

如果你有大量数据需要处理,最好先分析它们的分布并调整这些设置。

调整完毕后,将Integer替换为int可能会略微提高性能,但这更取决于JVM实现细节和硬件配置,而不是仅凭此项改进就能给你带来多少性能提升。


5
你后续要如何处理这些对象呢?如果你只是进行查找或类似的操作,将它们分开并检查两者可能会更快,而不是进行完整的复制。所以,
public static void callVoidMethod(Set<Integer> set) {

    Set<Integer> superset = new HashSet<Integer>();
    ...
    if (conditionSatisfied) superset.add(someValue);

    ...
    if(set.contains(value) || superset.contains(value))
        doSomething();

}

是的,我正在考虑这个问题,然后我递归调用这个方法 :) 因此,在这个方法中传递了太多的集合,我的想法是创建一个元素数组,这些元素是那些单独的哈希集合,例如:第一次调用该方法时,我传递一个包含一个集合的数组,然后创建第二个超级集合并将其添加到数组中,然后现在使用两个集合再次调用该方法... 但我面临着创建这样一个哈希集合数组的挑战。 - Sophie Sperner
1
递归调用肯定会增加复杂性。也许这对你最终尝试做的事情不起作用,但你可以在第一次调用该方法之前制作一个防御性副本集,传递该副本并允许其像您想要的那样添加到集合中。原始集合将保持不变,并且所有后续操作都将在第一个副本上进行。 - Carl
我终于实现了一个HashSet数组。所以感谢您的建议。 - Sophie Sperner

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