【问题标题】:String indexed collection in JavaJava中的字符串索引集合
【发布时间】:2009-03-18 15:03:59
【问题描述】:

使用 Java,假设为 v1.6。

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

我目前正在使用HashMap<String, Integer>,但我担心将 Integer 装箱/拆箱到 int 会使其变慢。

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

即而不是:

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

我可以的

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

有什么想法吗?有没有更快的方法来做到这一点?

附言我只会构建一次集合,也许会修改一次,但每次我都会知道大小,所以我可以使用 String[] 而不是 ArrayList 但不确定是否有更快的方法来复制 indexOf...

【问题讨论】:

    标签: java collections


    【解决方案1】:

    拆箱速度很快 - 无需分配。装箱可能会更慢,因为它需要分配一个新对象(除非它使用池化对象)。

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

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

    我建议使用 intValue() 而不是强制转换来将值转换为 int - 它可以更清楚地 (IMO) 发生了什么。

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

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

    【讨论】:

    • 让 Jon Skeet 给出一个让整个问题变得无关紧要的答案......
    • 看起来基准测试将是正确测试它的唯一方法。我不知道拆箱很便宜。我将不得不做一些分析来发现瓶颈。也就是说,基于 2 的内部结构应该更快 ArrayList.indexOf 或 HashMap.get
    • 抱歉,还有一条评论。这是一个重大的打击。我需要我能到达的每一微秒:)
    【解决方案2】:

    您无需装箱/拆箱而获得的任何性能提升都会被您需要使用 indexOf 方法的 for 循环显着消除。

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

    如果数组中有少量项目,数组就可以了,但是 HashMap 也是如此......

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          既然你说确实是瓶颈,那我建议Primitive Collections for Java;特别是,ObjectKeyIntMap 看起来正是您想要的。

          【讨论】:

            【解决方案6】:

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

            【讨论】:

              【解决方案7】:

              这里有个小问题:List 中可能有重复的元素。如果您真的想使用第二种方式,请考虑改用 Set。

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

              编辑:当然,最流行的 Set 类型(HashSet)本身是由 HashMap 支持的,所以切换到 set 可能并不是一个明智的改变。

              【讨论】:

              • 我自己在构建集合时管理重复项。集合无法工作,因为集合需要包含某种形式的键值对
              【解决方案8】:

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

              在内存中有大量Integer 对象可能是个问题。但是对于Strings(Stringchar[])也是如此。您可以自己定制 DB 风格的实现,但我建议先进行基准测试。

              【讨论】:

                【解决方案9】:

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

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

                public SimpleInt
                {
                    private final int data;
                
                    public SimpleInt(int i)
                    {
                        data = i;
                    }
                
                    // getter here
                    ....
                }
                

                【讨论】:

                  猜你喜欢
                  • 2011-06-09
                  • 2011-07-24
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-04-15
                  • 2012-12-01
                  • 1970-01-01
                  • 2023-04-07
                  • 1970-01-01
                  相关资源
                  最近更新 更多