【问题标题】:Store value in variable or call HashMap function? [duplicate]将值存储在变量中或调用 HashMap 函数? [复制]
【发布时间】:2018-09-21 22:13:29
【问题描述】:

当您需要在 for 循环中多次调用同一值的 HashMapget 时,将其存储在变量中或进行两次或三次调用会更有效吗?

【问题讨论】:

  • 我主要认为这是一种不必要的优化,并且这不太可能成为您的应用程序正在减速的部分。
  • 循环是否有可能迭代 3 次?还是 100 次,还是 100,000 次?这可以改变你的决定。我还喜欢将变量用于文档目的——如果我有一个 AccountID-to-PersonObject 的映射,我可能会使用类似final Person accountHolder = accounts.get(acctNumber);

标签: java performance hashmap


【解决方案1】:

假设您的键具有hashCode() 的合理实现,从HashMap 检索值是一个O(1) 操作。

如果您只检索此对象几次,则将其存储在局部变量中可能是一种微优化(阅读:过早优化),但您可能不会注意到任何不同之处。将此类对象存储在局部变量中的真正原因是避免重复检查映射中是否确实存在键、值不是 null 等的样板代码。

【讨论】:

  • +1 - 但是,即使 HashMap 是 O(1),也有 不可避免的开销,正如您所说的“检查密钥是否确实存在于地图中”并计算哈希码本身。我已经“修复”了其他人的代码,他们在循环中从地图中检索值,这显然是(IMO)将其存储在(final)变量中的原因。我喜欢的另一个原因是能够适当地命名变量。
【解决方案2】:

在 HashMap 中访问数据的时间是 O(1),所以总体来说还是相当快的。但是,如果您使用 HashMap 中的正确值启动一个变量,它会快一点。如果您使用某个键访问 HashMap,则首先调用该键的 hashCode 方法。如果你调用一次 - 它会更快。

我的经验表明,为这种情况准备变量是更好的解决方案,不仅因为性能目的,还因为重构。如果发生这种情况,您必须更改一些代码,您在 HashMap 调用中进行了一次更改,而不是在不同的行中进行了多次更改,通常会保留一行不变(这会导致错误)。

【讨论】:

    【解决方案3】:

    HashMap get 在恒定时间内运行。所以从效率的角度来看,这并不重要。虽然将值存储在变量中更简洁。

    【讨论】:

      【解决方案4】:

      调用 hashmap.get() 会创建一个间接引用,因此它会比直接变量引用慢。 hashmap.get() 具有 O(1) 复杂度的事实与这个问题的答案绝对无关,因为 O(1) 复杂度仅意味着算法的执行复杂度不会随着元素数量的增加而增加,但是,它没有说明一次运行需要多少个 cpu 周期,它只说明它是恒定的。 将结果存储在变量中可能是最高效的。

      【讨论】:

        【解决方案5】:

        我用HashMap<String, String> 做了一个简单的测试,其中键和值都是随机生成的 64 个字符的字符串。它在地图中使用 1.000.000 条记录,并在 2 个 for 循环中遍历每条记录:首先是调用一次 get() 并将其保存到变量中。其次是拨打get() 3 次。这是在 5 次迭代中完成的。

        结果(以毫秒为单位):

                              1    2    3    4    5      avg
        Store in a variable: 125  126  103  104  102  |  112
        Call 3 times:        151  135  137  134  152  |  142
        

        因此,对于这种配置(字符串映射),调用一次get() 并将结果存储在变量中更有效


        测试代码:

        ArrayList<String> keys;
        HashMap<String, String> data;
        
        void run() {
            generateData(1_000_000);
        
            long start, end;
        
            for (int i = 0; i < 5; ++i) {
                start = System.nanoTime();
                for (String key : keys) {
                    String value = data.get(key);
                }
                end = System.nanoTime();
                System.out.println("Store in a variable: " + ((end - start) / 1000 / 1000) + "ms");
        
                start = System.nanoTime();
                for (String key : keys) {
                    data.get(key);
                    data.get(key);
                    data.get(key);
                }
                end = System.nanoTime();
                System.out.println("Call 3 times: " + ((end - start) / 1000 / 1000) + "ms");
            }
        }
        
        void generateData(int size) {
            keys = new ArrayList<>(size);
            data = new HashMap<>(size);
            for (int i = 0; i < size; ++i) {
                String key = getRandomString(64);
                keys.add(key);
                data.put(key, getRandomString(64));
            }
        }
        
        String getRandomString(int length) {
            StringBuilder str = new StringBuilder();
            for (int i = 0; i < length; ++i) {
                str.append((char) ThreadLocalRandom.current().nextInt(128));
            }
            return str.toString();
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-08-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多