Java中的字符串索引集合

时间:2009-03-18 15:03:59

标签: java collections

使用Java,假设v1.6。

我有一个集合,其中唯一索引是一个字符串,非唯一值是一个int。 我需要尽快对这个集合执行数千次查找。

我目前正在使用HashMap<String, Integer>,但我担心Integer to int的装箱/拆箱会让它变慢。

我原本想过使用ArrayList<String>加上int[]

即。而不是:

int value = (int) HashMap<String, Integer>.get("key");

我能做到

int value = int[ArrayList<String>.indexOf("key")];

有什么想法?有更快的方法吗?

P.S。我只会构建一次集合并且可能会修改一次,但每次我都知道大小,所以我可以使用String[]而不是ArrayList,但不确定是否有更快的方法来复制indexOf ... < / p>

9 个答案:

答案 0 :(得分:13)

取消装箱很快 - 不需要分配。拳击是一个可能较慢的,因为它需要分配一个新对象(除非它使用一个池)。

你确定你真的遇到了问题吗?在您确实证明这是一个重大的打击之前,不要使您的代码复杂化。我非常怀疑它是。

有可用于基本类型的集合库,但我会坚持使用JRE中的普通HashMap,直到您进行了分析并检查这是否会导致问题。如果真的只有数千的查找,我非常怀疑这将是一个问题。同样,如果你是基于查询而不是基于加法(即你获取的次数比你添加的更多),那么装箱费用不会特别重要,只需拆箱,这很便宜。

我建议使用intValue()而不是强制转换来将值转换为int - 这样可以更清楚地显示(IMO)正在发生的事情。

编辑:要回答评论中的问题,当集合足够大时,HashMap.get(key)将比ArrayList.indexOf(key) 更快。如果你实际上只有五个项目,那么列表可能会更快。我认为事实并非如此。

如果你真的,真的不想要装箱/拆箱,试试Trove(TObjectHashMap)。还有COLT要考虑,但我找不到合适的类型。

答案 1 :(得分:3)

通过使用indexOf方法进行的for循环,您可以从不必使用box / unbox获得的任何性能提升都被显着删除。

使用HashMap。此外,您不需要(int)强制转换,编译器会为您处理它。

数组的东西可以用数组中的少量项目,但HashMap也是如此......

你可以快速查找数组的唯一方法(这是不是一个真正的建议,因为它有太多的问题)是你使用String的hashCode来工作作为数组的索引 - 甚至不要考虑这样做! (我只提到它,因为你可能会通过谷歌找到一些东西来讨论它...如果他们不解释为什么它不好不再阅读它了!)

答案 2 :(得分:1)

我猜想HashMap可以提供更快的查找速度,但我认为这需要一些基准测试才能正确回答。

编辑:此外,没有涉及拳击,只是对已经存储的对象进行拆箱,这应该非常快,因为在该步骤中没有完成对象分配。所以,我认为这不会给你更多的速度,但你应该运行基准测试。

答案 3 :(得分:1)

我认为扫描你的ArrayList以找到你的“密钥”的匹配将比你的装箱/拆箱问题慢得多。

答案 4 :(得分:1)

既然你说它确实是一个瓶颈,我会建议Primitive Collections for Java;特别是,ObjectKeyIntMap看起来就像你想要的那样。

答案 5 :(得分:1)

如果构建地图一次又一次的成本无关紧要,您可能需要查看perfect hashing,例如Bob Jenkins' code

答案 6 :(得分:0)

这里有一个小问题:您可以在列表中包含重复的元素。如果您真的想以第二种方式进行,请考虑使用Set。

话虽如此,您是否对两者进行了性能测试,看看是否比另一个更快?

编辑:当然,最受欢迎的Set类型(HashSet)本身由HashMap支持,因此切换到一个集合可能不是一个明智的改变。

答案 7 :(得分:0)

List.indexOf将对列表进行线性扫描 - 通常是O(n)。二进制搜索将在O(log n)中完成工作。哈希表将在O(1)中完成。

在内存中包含大量Integer个对象可能是个问题。但是String s(Stringchar[])也是如此。你可以做自己的自定义数据库风格的实现,但我建议首先进行基准测试。

答案 8 :(得分:0)

地图访问不会对查找进行拆箱,只有稍后对结果的访问才会使其变慢。

我建议为int引入一个带有getter的小包装器,例如SimpleInt。它保持int而不转换。构造函数并不昂贵,总体上比整数更便宜。

public SimpleInt
{
    private final int data;

    public SimpleInt(int i)
    {
        data = i;
    }

    // getter here
    ....
}